-
Notifications
You must be signed in to change notification settings - Fork 2
NEP7 First Class Functions
First class functions have several related aspects:
- Functions as arguments
- Functions as return values
- Named nested functions
- Anonymous nested functions
- Closures
- Partial application
Neon currently supports functions as arguments, functions as results, and named nested functions. This proposal addresses anonymous functions, closures, and partial application.
An anonymous function is a function that is not bound to an identifier.
This can be done by introducing a new expression type which contains statements in the same way as a named function.
LET f: FUNCTION(s: String) := NEW FUNCTION(s: String)
print("hello \(s)")
END FUNCTION
f("world")
LET f: FUNCTION(s: String) := LAMBDA(s: String)
print("hello \(s)")
END LAMBDA
f("world")
In either case, the function will be compiled into object code in the same way as if it had a name.
A closure is a way of capturing an instance of a function along with its environment for later execution.
FUNCTION odd_generator(): FUNCTION(): Number
VAR x: Number := 1
RETURN NEW FUNCTION(): Number
VAR r: Number := x
x := x + 2
RETURN r
END FUNCTION
END FUNCTION
The above example would be compiled into something like the following:
TYPE odd_generator_captures IS RECORD
x: Number
END RECORD
FUNCTION odd_generator_1(INOUT captures: odd_generator_captures): Number
VAR r: Number := captures.x
captures.x := captures.x + 2
RETURN r
END FUNCTION
FUNCTION odd_generator(): FUNCTION(): Number
VAR x: Number := 1
VAR captures: odd_generator_captures
captures.x := x
RETURN $make_lambda(odd_generator_1, captures)
END FUNCTION
The captured variables are collected into the odd_generator_captures record. This record is carried along with the actual function by the new function generated by the hypothetical $make_lambda function. When this type of function is called, the captures in the function are supplied to the lambda function that is called.
The partial application operation creates a new function from an existing function by supplying fixed values for some of the arguments to the function.
With anonymous functions, partial application is mostly a syntactic convenience. The following two statements would act the same way:
FUNCTION add(x, y: Number): Number
RETURN x + y
END FUNCTION
LET add3a: FUNCTION(x: Number): Number := LAMBDA(x: Number)
RETURN add(3, x)
END LAMBDA
LET add3b: FUNCTION(x: Number): Number := PARTIAL add(3)