Functional
Type
Functional is a collection of types that can hold a function or a closure. To denote the type of function that takes
parameters S, T
(U
, V
, ...) and has a return type R
, the following syntax is used:
(S, T) -> R
The return type is mandatory, even if it equals Unit
. If the function takes no parameters, the parentheses are empty:
() -> R
Assignability
To initialize a variable of a functional type, one can use an anonymous function, non-member function, or a protocol method.
Given
function foo(x: Number, y: Text) returns Boolean -> {
return x.toText() == y;
}
The following assignments are OK because the types match
var a: (Number, Text) -> Boolean = foo;
var b: (Number) -> Text = function(x: Number) returns Text -> x.toText();
But these are not
var q: (Number, Number) -> Boolean = foo; // ERROR, 2nd argument type mismatch
var r: (Number, Text, Number) -> Boolean = foo; // ERROR, missing argument
var s: (Number) -> Boolean = foo; // ERROR, extra argument
var t: (Number, Text) -> Number = foo; // ERROR, incorrect return type
The functional type (P_1, P_2, ... P_n) -> R
is assignable to (Q_1, Q_2, ..., Q_m) -> S
(but not necessarily vice
versa) if the following conditions are satistifed:
n
=m
- for each
i
from1
ton
,Q_i
is assignable toP_i
R
is assignable toS
In other words, one can assign a function that takes contravariant (wider) types as arguments, and returns covariant ( narrower) type.
Given
union U { Number, Text }
function fun1(u: U) returns Text -> { return u.toText(); }
function fun2(a: Number) returns U -> { return a; }
function fun3(a: Number) returns Number -> { return a; }
function fun4(a: Number) returns U -> { return a; }
The following assignments are OK
var a: (Number) -> Text = fun1; // OK, Number is narrower than U
var b: (Number) -> U = fun3; // OK, U is wider than Number
However, var b: (U) -> U = fun2
is not allowed because U
is wider than Number
, and
var d: (Number) -> Number = fun4
is not allowed because Number
is narrowed than U
.
Protocol functions may be assigned as well, since they close over this
( see
Closures).
protocol [p] Proto() {
function foo(x: Number) -> {}
permission [p] bar(y: Number) {}
function implicit() -> {
var a: (Number) -> Unit = foo;
}
function explicit() -> {
var a: (Number) -> Unit = function(b: Number) returns Unit -> { this.bar['a'](b); };
}
}
Actions cannot be assigned to a functional variable (so a function containing var a: (Number) -> Unit = bar
is
illegal).
Invocation
To invoke a functional simply supply the comma-separated list of arguments in parentheses as if it was a regular function.
struct A {
x: (Number) -> Number
}
function apply(a: A, x: Number, b: (Number, Number) -> Number, y: Number, z: Number) returns Number -> {
return a.x(x) + b(y, z);
}