Functions

In general, a function in Minilang is any value that can be called with 0 or more arguments, causing some computation or evaluation resulting in a single value (or an error). Functions in Minilang are first-class values that can be assigned to variables, stored in lists / maps, etc and passed to other functions as arguments. They can also be composed using various infix operators. Some types of values such as integers, methods and types are also functions in Minilang.

Closures

Functions are created in Minilang using a fun-expression.

The final expression in a fun-expression is the body of the function. The body can reference variables declared outside the function; when a fun-expression is evaluated, it returns a closure which combines the function code with the current values of any such variables.

When a closure is called, the supplied arguments are bound to the function parameters before the body is evaluated. The following rules are applied when binding arguments to parameters, starting with the first argument and parameter.

  • If a list parameter (written as [Identifier]) is present, it is assigned a new empty list

  • If a map parameter (written as {Identifier}) is present, it is assigned a new empty map

  • For each argument

    • Otherwise if the next argument is named then

      • if is a parameter with the same name then the argument is bound to the parameter,

      • otherwise if there is a map parameter, the named argument is added to that parameter's value,

      • otherwise an error is returned.

    • Otherwise if there is another normal (not a map or list) parameter, the argument is bound to the parameter

      • if a type was specified for the parameter (using : expression), the argument type is checked against the specified type and if it is not the same or a sub-type, an error is returned

      • if ref is present, the argument is not dereferenced first, allowing the original variable to be modified by assigning to the paramter,

      • otherwise if var is present, the argument is dereferenced and put into a new variable that is bound to the parameter, allowing the parameter to be reassigned but not affected the original value,

      • otherwise the argument is dereferenced and bound to the parameter

    • Otherwise if there is a list parameter, the argument is added to that parameter's value,

    • Otherwise the argument is ignored.

  • All remaining normal parameters are set to nil,

  • Any parameters which have been bound to nil and have default expressions (written as := expression) are assigned the value of their default expressions (evaluated each time the closure is called),

  • Finally the closure body is evaluated.

  • If a type was specified for the closure (using : expression), the type of the result is checked and an error returned if it does not match,

  • Otherwise if the result types matches or no type was specified, the result is returned.

Calling Functions

Functions are called in Minilang using traditional postfix notation. Named arguments are passed using Name is Value, where Name is an identifier or a string.

1test("Hello world\n", option is true)

If the last argument is an anonymous function, ; can be used to denote the end of the arguments and the start of the parameters of the anonymous function, with the body of the anonymous function then placed after call.

1array::int32([4, 3]; I, J) I * 10 + J

Partial Functions

Simple functions can be written in Minilang using blank expressions, written as a single underscore _. Specifying _ as one or more arguments in a function call results in a partial function instead.

1let print_line := print("<", _, ">\n")
2
3print_line("Hello world")
<Hello world>

Since infix and indexing operations are also function calls, they can also be used with _ to create partial functions.

1_ + 1
2_[1]