langur

function declarations

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 purity

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.

closures

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

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{+}

nil left partially implied functions

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}

recursion

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(), fold(), and foldfrom() functions, or loops, can often be used instead of recursion.

return value

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).

function calls

Functions can be called with parentheses, such as x().

In statement context, functions can be also called with an unbounded argument list, such as split re/[!_]/, "a!b_c" which would split the string "a!b_c" into a list of 3 strings.

writeln "filtered: ", filter(fn{div 2}, arr) # 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.