Functions with parameters may be defined as shown in the examples below.
fn(x, y) { x + y } fn x, y: x + y
Functions without parameters may be defined as shown in the examples below.
fn() { 123 } fn: 123
When using parentheses to define parameters (long form), curly braces are required to define the function body. The simple, or short form, without parentheses, requires a colon between parameters and the body of the function. With the short form, curly braces are not required if the body of the function is a single expression.
By default, function parameters are immutable.
To make a parameter mutable, precede the parameter name with a var token within the parameter list.
fn(x, y) { ... } # x and y immutable
fn(var x, y) { ... } # x mutable and y immutable
fn(var x, var y) { ... } # x and y mutable
Langur parameters fall into the following categories.
You can define optional parameters after positional parameters using the assignment syntax to define a default value for them.
val addto = fn(a, b=3) { a + b }
Optional arguments are always passed with the name (using assignment syntax), and positional arguments are never passed with the name.
addto(1)
addto(1, b=12)
Arguments using the name are not order-dependent (as long as they come after positional arguments), and any of them can be left out (except for required parameters by name).
An external name of a parameter by name can be preserved while changing the internal variable name, using the as keyword. An external name specified this way may also be the same as a keyword, since the context makes the meaning clear. The internal name is used within the function and the external name is used in the call.
val x = fn(a as c=123) { a } # a used internally x(c=9) # c used in call
This allows you to change a parameter name internally and not break an API in the process.
Parameters by name should not be confused with argument/parameter expansion, which only applies to positional arguments and parameters.
You can require a parameter that also must use the name (not positional). To do this, use the alias, but do not specify a default value. If you specify a default value, it is an optional parameter.
val x = fn(a as a) { a } # no default value for a; not optional and not positional x(a=9) # a required in call
You can use a ... operator on the last positional argument passed to a function, to expand a list argument into multiple arguments. This precedes any optional arguments passed.
val x = [[21, 7], [42, 14], [96, 21]] zip(x...) # result == [21, 42, 96, 7, 14, 21]
zip(mapX([7], [14, 21], by=fn ... x: x)...) # result == [7, 7, 14, 21]
You can use the ... operator for parameter expansion. This allows a user-defined function to receive a variable number of arguments. The last arguments of the function will be placed into a single list. This also allows for setting limits for this expansion (with a default range of 0 to unlimited). -1 indicates unlimited for this purpose. See the following examples.
val a = fn(... x) { } # accepts 0 or more arguments val b = fn(...[1..9] x) { } # accepts 1 to 9 arguments val c = fn(x, ...[4] y) { } # accepts 5 arguments val d = fn(x, ...[2 .. ] y) { } # accepts 3 or more arguments val e = fn(x, ...[2 .. 6] y) { } # accepts 3 to 7 arguments
Argument/parameter expansion is considered to be positional and does not conflict with parameters by name.