Functions are first-order and can be anonymous. Both user-defined functions and built-in functions can be passed around as values.
The fn token designates a function definition.
Functions may be defined as shown in the examples below. There are several useful parameter options.
fn(x, y) { x + y } fn x, y: x + y fn() { 123 } fn: 123
Function impurity is explicit and requires the * token, such as follows.
fn*(x) { writeln x }Langur puts restrictions on the use of impure functions.
There are different kinds of impurity, but langur presently has only one. There is the setting of values outside of function scope, and there are the other "side effects," such as writing to the console or a file. So far, langur only has the "side effects" impurity.
Functions defined to use values outside their boundaries are closures. After a closure is defined, it is not affected by changes to those outside values.
fn(y) { x + y } # 1 parameter and closure on 1 value fn() { x + y } # no parameters (closure on 2 values)
Operator implied functions are defined without parentheses or spacing, using curly braces with an infix operator, such as fn{*}. This is the same as writing fn(x, y) { x * y } (2 implied parameters).
fn{+}
These are very similar to operator implied functions, but include a value on the right (1 implied parameter), such as fn{*3} to multiply a passed value by 3.
fn{+3}
There are a couple of ways to do recursion. In the following example, the function definition is directly assigned to a variable.
val fibonacci = fn(x) { if x < 2 { x } else { fibonacci(x - 1) + fibonacci(x - 2) }}
Recursion can also be used by making a call with the fn token and double parentheses. Using this method, recursion does not require assignment (may be used with anonymous functions).
val fibonacci = fn(x) { if x < 2 { x } else { fn((x - 1)) + fn((x - 2)) }} # or shortened to... val fibonacci = fn x: if(x < 2: x ; fn((x - 1)) + fn((x - 2)))
The built-in map() and fold() functions, or loops, can often be used instead of recursion.
An explicit return can be used, but a function's last value is its implicit return value.
All functions return something, even if it's nothing (null).
Functions can be called with parentheses, such as x().
In statement context, functions can be also called with an unbounded argument list.
writeln "filtered: ", filter(arr, by=fn{div 2}) # writeln using an unbounded argument list in statement context # filter not in statement context; using parentheses for call
Another way to make a function call (with one parameter) is to use the forwarding operator.
val s = x -> number # x forwarded to the number function in expression context
If you do not use an unbounded list or parentheses on a function name, it is not a call, but a reference to the function.