On this page:
Function
Function.of_  arity
#%call
#%call
fun
fun
fun
Function.map
Function.for_  each
Function.pass
Callable
8.12

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.

The . operator can be used on a function expression as equivalent to calling Function functions:

f.map(args, ...)

 is 

Function.map(f, args, ...)

f.for_each(args, ...)

 is 

Function.for_each(f, args, ...)

The Function annotation matches any function.

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.

> math.cos is_a Function

#true

> math.cos is_a Function.of_arity(1)

#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

fun_expr #%call (arg, ...)

 

repetition

fun_expr #%call (repet_arg, ...)

 

arg

 = 

arg_expr

 | 

keyword: arg_expr

 | 

repet , ellipses

 | 

& list_expr

 | 

~& map_expr

 

ellipses

 = 

ellipsis

 | 

ellipses , ellipsis

 

ellipsis

 = 

...

A function call. Each arg_expr alone is a by-position argument, and each keyword: arg_expr combination is a by-keyword argument. Function calls can serve as repetitions, where repet_arg is like arg, but with repetitions in place of expressions.

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

fun id_name(bind, ...):

  body

  ...

 

definition

fun id_name case_maybe_kw_opt

 

definition

fun

| id_name case_maybe_kw

| ...

 

definition

fun id_name maybe_res_annot

| id_name case_maybe_kw

| ...

 

expression

fun (bind, ...):

  body

  ...

 

expression

fun case_maybe_kw_opt

 

expression

fun maybe_res_annot

| case_maybe_kw

| ...

 

case_maybe_kw_opt

 = 

(bind_maybe_kw_opt, ..., rest, ...) maybe_res_annot:

  body

  ...

 

case_maybe_kw

 = 

(bind_maybe_kw, ..., rest, ...) maybe_res_annot:

  body

  ...

 

bind_maybe_kw_opt

 = 

bind

 | 

keyword: bind

 | 

bind = default_expr

 | 

bind: default_body; ...

 | 

keyword: bind = default_expr

 | 

keyword: bind: default_body; ...

 | 

keyword

 | 

keyword = default_expr

 

bind_maybe_kw

 = 

bind

 | 

keyword: bind

 | 

keyword

 

maybe_res_annot

 = 

:: annot

 | 

:~ annot

 | 

:: values(annot, ...)

 | 

:~ values(annot, ...)

 | 

:: (annot, ...)

 | 

:~ (annot, ...)

 | 

ϵ

 

rest

 = 

repet_bind , ellipsis

 | 

& list_bind

 | 

~& map_bind

 

ellipsis

 = 

...

Binds id_name as a function in the expr space, or when id_name is not supplied, serves as an expression that produces a function value.

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.

fun f(x):

  x+1

> f(0)

1

fun List.number_of_items(l):

  List.length(l)

> List.number_of_items(["a", "b", "c"])

3

def identity = fun (x): x

> identity(1)

1

fun curried_add(x):

  fun (y):

    x + y

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

fun f(x, y = x+1):

  [x, y]

> f(0)

[0, 1]

> f(0, 2)

[0, 2]

fun transform([x, y],

              ~scale: factor = 1,

              ~dx: dx = 0,

              ~dy: dy = 0):

  [factor*x + dx, factor*y + dy]

> transform([1, 2])

[1, 2]

> transform([1, 2], ~dx: 7)

[8, 2]

> transform([1, 2], ~dx: 7, ~scale: 2)

[9, 4]

fun invalid(x = 1, y):

  x+y

fun: default-value expression missing

fun

| valid(y): valid(1, y)

| valid(x, y): x+y

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

fun

| hello(name):

    "Hello, " +& name

| hello(first, last):

    hello(first +& " " +& last)

> hello("World")

"Hello, World"

> hello("Inigo", "Montoya")

"Hello, Inigo Montoya"

fun

| is_passing(n :: Number): n >= 70

| is_passing(pf :: Boolean): pf

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

fun

| is_sorted([] || [_]):

    #true

| is_sorted([head, next, & tail]):

    head <= next && is_sorted([next, & tail])

> is_sorted([1, 2, 3, 3, 5])

#true

> is_sorted([1, 2, 9, 3, 5])

#false

fun

| is_sorted([] || [_]):

    #true

| is_sorted([head, next, tail, ...]):

    head <= next && is_sorted([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.

fun hello :: String

| hello(name):

    "Hello, " +& name

| hello():

    #false

> hello("World")

"Hello, World"

> hello()

hello: result does not satisfy annotation

  result: #false

  annotation: String

fun things_to_say :: (String, String)

| things_to_say():

    values("Hi", "Bye")

| things_to_say(more):

    values("Hi", "Bye", more)

> 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

fun (bind, ...):

  body

  ...

 

entry point

fun case_maybe_kw_opt

 

entry point

fun maybe_res_annot

| case_maybe_kw

| ...

The entry point form of fun is the same as the expression form of fun.

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

fun Function.map(f :: Function,

                 args0 :: List, args :: List, ...)

  :: List

 

function

fun Function.for_each(f :: Function,

                      args0 :: List, args :: List, ...)

  :: Void

Applies f to each element of each args (including args0), iterating through the args lists together, so f must take as many arguments as the number of given args lists. For Function.map, the result is a list constaining the result of each call to f in order. For Function.for_each, the result is #void, and the result of each call to f is ignored.

> Function.map(fun (x, y): x + y, [1, 2, 3], [4, 5, 6])

[5, 7, 9]

> (fun (x, y): x + y).map([1, 2, 3], [4, 5, 6])

[5, 7, 9]

> println.for_each([1, 2, 3])

1

2

3

function

fun Function.pass(& _, ~& _) :: Void

Accepts any arguments and returns #void.

Provided only in the class space, not the annot or namespace space.

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:

class Posn(x, y):

  private implements Callable

  private override method call(dx, dy):

    Posn(x + dx, y + dy)

> def p = Posn(1, 2)

> p

#<function:Posn>

> p(3, 4)

#<function:Posn>