Gnomon 2.2 — Language Definition

This document presents a complete but brief overview of version 2.2 of the Gnomon scripting language. Some examples are included, but it is strongly recommended that the reader works through the sample session and Project Euler solutions presented on the main page for a more thorough set of examples.

(back to main)

Contents

System commands

Datatypes

Variables

Operators

Expressions

Input/output

Special commands

Flow control

Enhanced types

Arrays

Dictionaries

Stacks

Strings

User defined functions

Inbuilt functions

System commands

System commands are used to configure aspects of the interpreter or to interact with the host system, and are prefixed by a forward slash.

FunctionCommandDescription
//CommentIndicates all subsequent entry on the current line is comment
/cd dirChange directory*change working directory to 'dir'
/d nSet denominatorSet max denominator to n for decimal to rational conversion. If the argument is missing or invalid, the default value of 1000000 is used.
/fFraction printingToggle printing fractions as decimals.
/h commandHelpReturn a description of the given command
/l nSet print lengthSet the max length for printed value strings
/pImplicit printingToggle implicit printing of command results
/qQuit*Quit the interpreter
/r abcRun scriptRun script file "abc"
/s abcShell command*Execute shell command "abc"
/tTime calculationsPrint out the time taken by the calculations
/vVersionPrint the version number

*Command is not supported on the iPhone or iPad

(back to top)

Datatypes

Gnomon includes native support for the five numeric types, as well as a special, single valued type to represent any uninitialised or invalid value.

TypeDescription
NaNrepresents any uninitialised or invalid value
byte8 bit unsigned type
integersigned integer
rationalinteger numerator over integer denominator
decimalfloating point representation of a real number (native double type)
complexfloating point complex number

(back to top)

Integers are represented using the native long word type unless too large, in which case an arbitrary precision representation is used. Conversion is automatic for appropriate pure integer operations, however many functions that work with integers will either fail with an arbitrary precision integer argument, or convert to decimal prior to evaluation. Explicit support for arbitrary precision integers is implemented in all basic arithmetic operations and rational powers, as well as calculation of factorials, binomial coefficients, LCMs, GCDs and factorisation.

Arbitrary precision is not supported for rational and complex types.

(back to top)

Variables

Named variables are assigned using the ~ operator. User-defined variables must start with a lowercase letter and be comprised of alphanumeric characters only. The $ symbol is used to represent the result of the last complete calculation, and assignment to . clears a defined variable.

(back to top)

Operators

Operators (in order of precedence)

OperatorsDescription
+copy
^exponent
-unary minus
!logical negate
!!bit negate
++, --increment and decrement (no pre/post distinction)
*, /, %, /%multiply, divide, modulus and integer division
**matrix multiply
+, -add and subtract
<<, >>shift left and shift right
??type
<, >less than and greater than
<=, >=less than or equal, greater than or equal
=, !=equal, not equal
&&, ^^, ||bit and, bit xor, bit or
&, |logical and, logical or
(...)brackets for grouping

Note that the bit boolean operators are consistently a doubled version of the associated logical operator.

(back to top)

Expressions

An expression is any syntactically correct sequence of values, operators and identifiers that defines a calculation. Distinct expressions on a single line are separated by a ; character. Types are inferred and automatic numeric promotion is applied where appropriate.

Interaction with the interpreter is by entering (or reading from a text file) a sequence of expressions to be calculated.

(back to top)

Input/output

CommandDescription
]An instruction to print the value of the following expression with a new line
]XXX,YYYprints with a single space separation on the same line
]XXX:YYYprints without separation on the same line
]%XXXprints and suppresses the following new line
@prompt for a value to be entered

Recall that if implicit printing is on (see System Commands) then the result of any non-assignment expression will be printed automatically.

(back to top)

Basic Calculation Examples

Here are some example calculations illustrating numeric datatypes, expressions, and the simple use of variables.
# // set implicit printing for calculator like operation
# /p
Implicit printing on
# 7 + 3^2 * 2
25
# 26 / 6 - 4
1/3
# Dec $
0.33333333333333
# 0.5 * 0.72
0.36
# Frac $
9/25
# (3 + 2*I) * (3 - 2*I)
13
# a ~ 3 + 2*I
# b ~ 3 - 2*I
# c ~ a * b
# ]a,b,c
(3+2i) (3-2i) 13
# 253^25
1196776435607632482790118858840382391829660917532091147865693
# 23481729348712983749123847123 * 9812793847238273418273
230421369275565156221292747340623890303817486678579
#

(back to top)

Special commands

CommandDescription
]]print all user-defined variables and functions
..clear all user-defined variables and functions

These commands may not form part of an expression, but must comprise the entire input line on entry.

(back to top)

Flow control

Conditional and repeat evaulation of expressions is controlled by the following operators:

CommandDescription
? {X} {Y}If expression X evaluates true (i.e. non-zero) then expression Y is evaluated.
?: {X} {Y} {Z}If expression X evaluates true (i.e. non-zero) then expression Y is evaluated, otherwise expression Z is evaluated.
?+ {X} {Y}While expressions X evaluates true, evaluate expression Y.
?+ n {Y}Evaluate expression Y n times, where n is either an integer valued constant or expression.
?+ a {Y}For a an array (see Enhanced types), evaluate Y once for each element in the array.

For all of these, the return value is the value of the last expression evaluated. The >< operator in the {Y} expression will terminate the loop, and within a loop, the symbol _ acts as an identifier representing the current innermost loop index (up to 10 levels of nesting supported).

If the loop has the form ?+ a {Y} where a is an array of any type, the expression Y is evaluated once for each element of the array a, and the implicit loop variable _ returns each array element in turn.

If the conditional expression X is an array or stack, the check is for non-empty.

(back to top)

Flow Control Examples

The following example session illustrates some uses of the conditional operators:
# a~11
# // if a is greater than 10, set it to a mod 10
# ? {a > 10}{a ~ a%10}
# // print the resulting value of a
# ]a
1
# // if a is greater than 10, set it to a mod 10, otherwise add 10 to its value
# ?: {a > 10}{a ~ a % 10}{a ~ a + 10}
# ]a
11
# // while a is greater than 5, print it and reduce its value by 1
# ?+ {a > 5}{]a;a--}
11
10
9
8
7
6

# // loop 5 times, printing the implicit loop counter and its square
# ?+ 5{]_,_^2}
1 1
2 4
3 9
4 16
5 25

# // create the array [1 2 3 4 5]
# b ~ [1:5]
# // loop through its elements, printing them and their squares
# ?+ b{]_,_^2}
1 1
2 4
3 9
4 16
5 25

#

(back to top)

Enhanced types

Four enhanced types are supported — character strings and three collection types. The collections types can contain values of both basic and enhanced type.

CommandDescription
arrayindexed collection of values of any type
stackLIFO stack of values of any type
stringNULL(0) terminated string of characters
dictionarypair of equal length arrays, the first providing the keys and the second the values

The ?? operator will return the type of any given expression as a string.

(back to top)

Arrays

There are 4 ways to declare and (optionally) initialise an array.

CommandDescription
[[n]]An array of n uninitialised values, where n is an integer constant, variable or expression. If n is a stack, then each entry is added to the array
[i:j]An array of values from i to j in steps of 1 (i, j constants or expressions)
[i:j:k]An array of values from i to j in steps of k (i, j, k integer, rational or float constants or expressions)
a~[l m n...]An array initialised to contain the specific values listed (l, m, n constants or bracketed expressions)

Arrays support all standard operations, either applying to correponding elements for equal-length arguments, or applying a single value across all array elements. In addition, the following operations for acting on the array explicitly are also available:

OperatorOperationDescription
'indexinteger constant or integer array argument for element selection
#sizereturns the number of elements in the array
:headreturns the first element of the array
`tailreturns all but the first element of the array
<-index inx <- a returns the index of x in array a, or false ($0) if not present
::appenda::b appends the value or array b to the array a
##choosea##b returns those entries from array a selected by the non-zero elements of the byte array b

Arrays can be passed in place of single value function arguments where it makes sense — the functions will map over all values. However, this can lead to some unexpected results when the argument is interpreted literally as an array. For example, consider the expression:

?: {x%2}{"odd"}{"even"}
that evaluates to "even" if x is an even integer, and otherwise to "odd". If x is an array, it will not result in an array of corresponding strings "even" and "odd", but rather the conditional expression will simply test whether or not the array is empty. If this is not the desired behaviour, the standard library function Apply can be used to ensure the condition is evaluated element by element.

(back to top)

Dictionaries

Dictionaries associate an array of keys [k] with an (equally sized) array of values [v] and are defined using d ~ [k]->[v].

Most array operations have analagous version that applies to dictionaries.

OperatorOperationDescription
'keyd'key returns the associated value (analagous to arrays) and can be used in assignment and deletion
#sizereturns the number of elements in the dictionary
:keysreturns the key array (by analogy with head)
`valuesreturns the value array (by analogy with tail)
<-key invalue<-d returns the key for the given value in dictionary d
::appendAppends two dictionaries. This fails if there are duplicate keys.

(back to top)

Stacks

There are several stack specific operations.

OperatorOperationDescription
#depthreturns the number of elements in the stack
.pop<a b c ...> . → <b c ...>
@rot<a b c ...> @ → <b c a ...>
:dup<a b ...> : → <a a b ...>
/over<a b ...> / → <b a b ...>
\swap<a b ...> \ → <b a ...>
!neg<a b ...> ! → <-a b ...>

(back to top)

Strings

As shown in the following examples, some array functions and operators will also work with string arguments by treating the string as an array of characters.

(back to top)

Enhanced Type Examples

The following example session illustrates some of the ways to initialise and manipulate arrays and their elements, as well as the basics of working with a dictionary and with a string:
# // allocate a 3 element array - all values are uninitialised
# a~[[3]]
# ]a
[ NaN NaN NaN ]
# // set values for the first two elements
# a'1~5
# a'2~6
# ]a
[ 5 6 NaN ]
# // define a new array and initialise as an arithmetic sequence from 1 to 7 in steps of 2
# b~[1:7:2]
# ]b
[ 1 3 5 7 ]
# // and another from -1 to 0 in steps of 0.1
# c~[-1:0:0.1]
# ]c
[ -1 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0 ]
# //perform a calculation on all elements at once
# ]5 * c + 1
[ -4 -3.5 -3 -2.5 -2 -1.5 -1 -0.5 0 0.5 1 ]
# // array elements can be themselves arrays
# d ~ [1 7 b 26 [1 5 3]]
# ]d
[ 1 7 [ 1 3 5 7 ] 26 [ 1 5 3 ] ]
# // get the number of elements
# ]#d
5
# // select the 5th element
# ]d'5
[ 1 5 3 ]
# // loop through and print each element
# ?+ d {]_}
1
7
[ 1 3 5 7 ]
26
[ 1 5 3 ]

#
# // Now try using a dictionary
#
# keys ~ [1:5]
# values ~ [1:5]^2
# dict ~ keys->values
# ]dict
1->1
2->4
3->9
4->16
5->25

# // select entries where the key is even
# ]dict'keys##!(keys%2)
[ 4 16 ]
# // select entries where the value is greater than 10
# sel~keys##values>10
# ]sel->dict'sel
4->16
5->25

#
# // And now try a string
#
# s ~ "Hello World"
# ]:s
$48
# ]`s
ello World
# ]s'3
$6C
# ]s'[3:6]
lo W
# ]s::"X"
Hello WorldX
# ]Rev s
XdlroW olleH
#

(back to top)

User defined functions

Functions are defined using the syntax name () argument list, e.g.

f () a b ~ a * a + b
Compound expressions require braces
f () x y ~ { expr1; expr2;... }

A single explicit recursive call is supported, as well as a special recursive argument syntax with an explicit recursive block, and a base case block for the last entry in the input array:
f () x:xs ~ {x + f xs} {x}
Multiple recursive calls in the function definition are explicitly unsupported.

It is not possible to define a function using a name that is already being used by a variable, or vice versa.

If desired, parameter type info can be associated with function arguments by using the following forms in the argument list definition (compare the output of the ?? operator described in the section on enhanced types):

Global variables are not visible inside a function, and any new variables declared within a function body are local in scope and deleted on function exit. If access to a global is required, it's identifier must be prefixed with an underscore — i.e. _a will reference global variable a. Argument names in function definitions are merely markers to be replaced with generic, locally scoped identifiers on invocation.

Operators and Functions as Arguments

Function arguments may also be operators, defined using the syntax @<digit>, or other functions, defined using the syntax @<letter>.

For example, we can define a function that evaluates any single argument function given as its argument for value 3 using

f3 () @f ~ @f 3
and invoke it as
f3 @Log

Similarly a function that folds a list using an arbitrary binary operator can be defined using an operator parameter and recursive syntax

f () x:xs @1 ~ {x @1 f xs @1}{x}
and invoked as
f [1:4] +
or
f [1:4] *
for example.

There is no support for variables holding functions as values, but strings can be used to represent the function arguments as follows:

s~"@Log"; f3 s

Anonymous Functions

Some standard library functions, as well as user-defined functions as described above, require a function as an argument. An anonymous function is a convenient way to create a function that is not required to persist beyond the particular invocation and pass it in as the argument.

The syntax is an extension of the usual @<name> function argument syntax, but with the anonymous function body being included between following braces. Up to 9 parameters are supported, using the notation ?n with n ranging from 1 to 9. Expressions are supported, but any variables must be accessed using the global scope operator _.

For example,

Apply @{GDist 0 1 ?1} [1:10]
will perform exactly as if we had defined the function
f () x ~ GDist 0 1 x
and then called
Apply @f [1:10]

This example shows using an expression and accessing a variable

# a ~ [[10]]
# p ~ 0.5
# t ~ 10
# FnFill a @{BRand _p (10 * _t)}
[ 59 46 44 55 44 54 53 54 45 60 ]
Anonymous functions are particularly convenient for plotting
FLinePlot @{CCDF 0 1 ?1} [-5:5:0.1] AxesPlotDefs LineDefs
and random array generation
a~[[10]];FnFill a @{GRand 10 5}
The Apply2D function requires a 2 parameter function argument. In this next example an anoymous function is used to calculate the probability of up to 2 successes across a range of binomial trials (3 to 5 in this example) with probability of success from 10% to 50%:
# Apply2D @{BCDF 2 ?1 ?2} [3:5] [0.1:0.5:0.1]
[ 0.999 0.9963 0.99144
  0.992 0.9728 0.94208
  0.973 0.9163 0.83692
  0.936 0.8208 0.68256
  0.875 0.6875 0.5 ]
Here is a mutiple parameter example involving a user-defined function:
# // define a 4 parameter function
# g () a b c d ~ a * b * c * d
# // the f123 function calls a passed in 3 argument function with argument values 1, 2 and 3
# f123 () @f ~ @f 1 2 3
# // Use an anonymous function to map between the two — using a fixed value of 100 as the 1st argument to g
# f123 @{g 100 ?1 ?2 ?3}
600

Anonymous functions are not only useful for managing arguments to other functions, but can consist of arbitrary expressions involving the automatic parameters as in the following example:

# Apply2D @{?1^?2 + ?1} [1:3] [1:3]
[ 2  4   6
  2  6  12
  2  10 30 ]

(back to top)

Inbuilt functions

A comprehensive standard library of built in functions is provided and documented here. All inbuilt start with a capital and cannot be deleted or redefined.

(back to top)