Skip to content

NEP7 First Class Functions

Greg Hewgill edited this page Jul 25, 2019 · 1 revision

Concept

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.

Anonymous Functions

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.

Syntax alternative: NEW FUNCTION

LET f: FUNCTION(s: String) := NEW FUNCTION(s: String)
    print("hello \(s)")
END FUNCTION
f("world")

Syntax alternative: LAMBDA

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.

Closures

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.

Partial Application

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)

Clone this wiki locally