6.6 Functions
An expression followed by a parenthesized sequence of expressions is parsed as an implicit use of the #%call form, which is normally bound to implement function calls.
is
Function.map(f, args, ...)
is
Function.for_each(f, args, ...)
annotation | ||||||
| ||||||
annotation | ||||||
| ||||||
|
The Function.of_arity variant requires that each expr produces a nonnegative integer, and then function must accept that many by-position arguments. The function must require only keywords that are provided as keywords, and it must accept all keywords that are listed. Each keyword must be distinct.
#true
#true
> math.atan is_a Function.of_arity(1, 2)
#true
> (fun (x, ~y): #void) is_a Function.of_arity(1, ~y)
#true
> (fun (x, ~y): #void) is_a Function.of_arity(1)
#false
> (fun (x, ~y = 0): #void) is_a Function.of_arity(1)
#true
> (fun (x, ~y = 0): #void) is_a Function.of_arity(1, ~y, ~z)
#false
expression | |||||||||||||||
| |||||||||||||||
repetition | |||||||||||||||
| |||||||||||||||
| |||||||||||||||
| |||||||||||||||
| |||||||||||||||
| |||||||||||||||
|
If the arg sequence contains & list_expr or repet , ellipses, then the elements of the list or repetition are spliced into the call as separate by-position arguments.
If the arg sequence contains ~& map_expr, then all the keys in the immutable map produced by map_expr must be keywords, and they must not overlap with the directly supplied keywords or keywords in maps from other ~& map_expr arguments. The keyword-value pairs are passed into the function as additional keyword arguments.
See also use_static.
The #%call form is implicitly used when (…) is used in after another expression in an expression position. See also Implicit Forms.
> List.length([1, 2, 3])
3
> List.length #%call ([1, 2, 3])
3
definition | ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
definition | ||||||||||||||||||||||||
| ||||||||||||||||||||||||
definition | ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
definition | ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
expression | ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
expression | ||||||||||||||||||||||||
| ||||||||||||||||||||||||
expression | ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| ||||||||||||||||||||||||
|
The first case shown for the definition and expression forms shown above are subsumed by the second case, but they describe the most common forms of function definitions and expressions.
> f(0)
1
List.length(l)
> identity(1)
1
> curried_add(1)(2)
3
When | is not used, then arguments can have default values as specified after a = or in a block after the argument name. Bindings for earlier arguments are visible in each default_expr or default_body, but not bindings for later arguments; accordingly, matching actions are interleaved with binding effects (such as rejecting a non-matching argument) left-to-right, except that the result of a default_expr is subject to the same constraints imposed by annotations and patterns for its argument as an explicitly supplied argument would be. An argument form keyword = default_expr is equivalent to the form keyword: id = default_expr for the id with the same string form as keyword. A :: or :~ is not allowed in default_expr, unless it is nested in another term, since that might be misread or confused as an annotation in bind for an identifier; for similar reasons, bind and default_expr cannot contain an immediate =.
A constraint not reflected in the grammar is that all optional by-position arguments must follow all required by-position arguments. To define a function that works otherwise, use the | form.
> f(0)
[0, 1]
> f(0, 2)
[0, 2]
> transform([1, 2])
[1, 2]
> transform([1, 2], ~dx: 7)
[8, 2]
> transform([1, 2], ~dx: 7, ~scale: 2)
[9, 4]
> valid(2)
3
> valid(3, 2)
5
When alternatives are specified with multiple | clauses, the clauses can be provided immediately after fun or after the name and a maybe_res_annot as described further below.
> hello("World")
"Hello, World"
> hello("Inigo", "Montoya")
"Hello, Inigo Montoya"
> is_passing(80) && is_passing(#true)
#true
When a rest sequence contains & list_bind or repet_bind , ..., then the function or function alternative accepts any number of additional by-position arguments. For & list_bind, the additional arguments are collected into a list value, and that list value is bound to the list_bind. Static information associated by List is propagated to list_bind. For repet_bind , ..., each variable in repet_bind is bound to a repetition that repeats access to that piece of each additional argument. Only one by-position rest binding, & list_bind or repet_bind , ..., can appear in a rest sequence.
When a rest sequence contains ~& map_bind, then the function or function alternative accepts any number of additional keyword arguments. The additional keywords and associated argument values are collected into an immutable map value to be bound to map_bind. Static information associated by Map is propagated to map_bind. Only one ~& map_bind can appear in a rest sequence.
#true
| is_sorted([head, next, & tail]):
> is_sorted([1, 2, 3, 3, 5])
#true
> is_sorted([1, 2, 9, 3, 5])
#false
#true
| is_sorted([head, next, tail, ...]):
> is_sorted([1, 2, 3, 3, 5])
#true
> is_sorted([1, 2, 9, 3, 5])
#false
When maybe_res_annot is present, it provides an annotation for the function’s result, but only for the corresponding case if a maybe_res_annot is present in a multi-case function written with |. In the case of a checked annotation using ::, the function’s body is not in tail position with respect to a call to the function, since a check will be applied to the function’s result. When maybe_res_annot is present for a function declared with cases afterward, a maybe_res_annot applies to all cases, in addition to any maybe_res_annot supplied for a specific case. A maybe_res_annot that has a parenthesized sequence of annots (with our without values) describes multiple result values with an annotation for each individual result.
> hello("World")
"Hello, World"
> hello()
hello: result does not satisfy annotation
result: #false
annotation: String
> things_to_say()
"Hi"
"Bye"
> things_to_say("Nachos")
things_to_say: results do not satisfy annotation
results...:
"Hi"
"Bye"
"Nachos"
annotation: (String, String)
entry point | |||
| |||
| |||
entry point | |||
| |||
entry point | |||
|
A binding as an entry point allows a form to work and cooperate with contexts such as constructor that syntactically require a function. That is, an entry point is a syntactic concept. Its corresponding run-time representation is normally a function, but an entry point may need to be manipulated statically, such as adding an extra argument to make it serve as a method. Besides fun, the macro form is also bound as entry point.
function | |||
| |||
function | |||
> Function.map(fun (x, y): x + y, [1, 2, 3], [4, 5, 6])
[5, 7, 9]
[5, 7, 9]
1
2
3
An interface that a class can implement (publicly or privately) to make instances of the class callable as functions. The interface has one abstract method, which must be overridden to implement the behavior of function calls:
call —
receives the arguments that are passed to the instance that is called as a function, and the method’s result is the result of the function call.
class Posn(x, y):