Introduction

The Calculon language is extremely simple. There are three types, real, vector and boolean. Everything is explicitly typed (except that if you omit a type specifier, you get real. Everything is an expression. Variables are immutable and looping must be done via recursion.

The simplest way to think about a Calculon script is as a series of let statements followed by a return, but the details are a bit more complicated than that.

The following list describes the major syntactic elements:

  • 0 is a real constant.
  • true or false are boolean constants.
  • return must be the last keyword in a Calculon script. When seen, any output parameters are set and the scripts exit. You cannot use this inside a function.
  • [0, 1, 2] is a vector. The elements must be reals (but need not be constant). You may supply any positive, non-zero number of elements. The size of a vector is part of its type; vectors of different sizes are not compatible.
  • [*4 2] is also a vector; this has four elements, all of which are set to 2. The size of the vector must be a constant (but the value does not need to be).
  • sqrt(2) calls a function. Functions may take any number of parameters, of any type, and return a single parameter, of any type. Functions are not polymorphic.
  • V.x, V.y, V.z, V.w extract the first four elements from a vector. (Obviously assuming the vector has enough elements.) An out of bound access is a compile time error.
  • V[n] extracts the nth element of a vector. If the vector is square --- e.g. four, nine or sixteen elements --- you may also use V[x, y] to extract a given element by coordinate. The elements are stored in row-major order. Out of bound indices wrap.
  • V.length returns the number of elements in a vector.
  • V.sum computes the sum of all elements in the vector. (You can calculate the Pythagorean magnitude of a vector with sqrt(V*V), of course.)
  • let i = 1 in expr defines a variable that becomes available when evaluating expr. The new variable is does not have an explicit type and its type is inferred from its definition.
  • let v: vector*3 = [0, 1, 2] in expr defines a variable that becomes available when evaluating expr. The new variable is explicitly typed and if you try to define a variable with a type that differs from its declaration you will get an error. You must specify the size of vectors.
  • let f(v1:vector*3, v2:vector*3):vector*3 = v1 + v2 in expr defines a function. The new function is available both when evaluating expr and inside the function body, which allows recursion. Note that the scoping rules here are different to when you define a variable! Also note that type inference is not done on functions!
  • if booleanvalue then truevalue else falsevalue does conditional evaluation. If booleanvalue is true then truevalue is evaluated; otherwise falsevalue is evaluated. Both must have the same type.

In addition the usual set of infix and prefix operators are available:

  • For booleans: ==, !=, and, or, not. and and or are short-circuiting.
  • For vectors: ==, !=, +, -, *, /. the operation is applied to each component. If you're doing this, both parameters must have the same sized vector. For non-conditionals, if you pass a real as the second parameter, then that value is applied to all components.
  • For reals: all the usual C-like operators. Complain if you find any missing.

The order of precedence, from highest to lowest, is: unary operators, multiplication and division, addition and subtraction, comparisons, boolean operators, if...then...else, let.

The type signatures used for Calculon scripts is subtly different from the type signatures used for Calculon functions. Functions may return only one value, and their signatures look like this:

(x:real, y:real): vector*2

Scripts may return any number of parameters, and their signatures look like this:

(x:real, y:real): (v:vector*2, length:real)

It is perfectly acceptable for output parameters to have the same name as an input parameter (or a global variable).

Most of the standard maths library is bound. They all behave exactly like their Posix namesakes. As of writing, the list consists of:

  • acos()
  • acosh()
  • asin()
  • asinh()
  • atan()
  • atan2()
  • atanh()
  • cbrt()
  • ceil()
  • copysign()
  • cos()
  • cosh()
  • erf()
  • erfc()
  • exp()
  • exp2()
  • expm1()
  • fabs()
  • fdim()
  • floor()
  • fma()
  • fmax()
  • fmin()
  • fmod()
  • hypot()
  • j0()
  • j1()
  • lgamma()
  • log()
  • log10()
  • log1p()
  • log2()
  • logb()
  • nearbyint()
  • pow()
  • remainder()
  • rint()
  • round()
  • sin()
  • sinh()
  • sqrt()
  • tan()
  • tgamma()
  • trunc()
  • y0()
  • y1()

Previous page Next page