# Functional programming

## Function expression

A lambda expression or a gamma expression can be seen like a function object with no name. During the evaluation process, the expression object is evaluated as well as the arguments -- from left to right -- and a result is produced by applying those arguments to the function object. An expression can be built dynamically as part of the evaluation process.

(axi) println ((lambda (n) (+n 1)) 1) 2

The difference between a lambda expression and a gamma expression is only in the nameset binding during the evaluation process. The lambda expression nameset is linked with the calling one, while the gamma expression nameset is linked with the top level nameset. The use of gamma expression is particularly interesting with recursive functions as it can generate a significant execution speedup. The previous example will behaves the same with a gamma expression.

(axi) println ((gamma (n) (+n 1)) 1) 2

### Self reference

When combining a function expression with recursion, the need for the function to call itself is becoming a problem since that function expression does not have a name. For this reason, the writing system provides the reserved keyword `self` that is a reference to the function expression. We illustrate this capability with the well-known factorial expression written in pure functional style.

(axi) println ((gamma (n) (if (<= n 1) 1 (* n (self (- n 1))))) 5) 120

The use of a gamma expression versus a lambda expression is a matter of speed. Since the gamma expression does not have free variables, the symbol resolution is not a concern here.

### Closed variables

One of the writing system characteristic is the treatment of free variables. A variable is said to be free if it is not bound in the expression environment or its children at the time of the symbol resolution. For example, the expression `((lambda (n) (+ n x)) 1)` computes the sum of the argument `n` with the free variable `x`. The evaluation will succeeds if `x` is defined in one of the parent environment. Actually this example can also illustrates the difference between a lambda expression and a gamma expression. Let's consider the following forms.

trans x 1 const do-print nil { trans x 2 println ((lambda (n) (+ n x)) 1) }

The gamma expression `do-print` will produce `3` since it sums the argument `n` bound to 1, with the free variable `x` which is defined in the calling environment as `2`. Now if we rewrite the previous example with a gamma expression the result will be one, since the expression parent will be the top level environment that defines `x` as 1.

trans x 1 const do-print nil { trans x 2 println ((gamma (n) (+ n x)) 1) }

With this example, it is easy to see that there is a need to be able to determine a particular symbol value during the expression construction. Doing so is called closing a variable. Closing a variable is a mechanism that binds into the expression a particular symbol with a value and such symbol is called a closed variable, since its value is closed under the current environment evaluation. For example, the previous example can be rewritten to close the symbol `x`.

trans x 1 const do-print nil { trans x 2 println ((gamma (n) (x) (+ n x)) 1) }

Note that the list of closed variable immediately follow the argument list. In this particular case, the function `do-print` will print `3` since `x` has been closed with the value `2` has defined in the function `do-print`.

### Dynamic binding

Because there is a dynamic binding symbol resolution, it is possible to have under some circumstances a free or closed variable. This kind of situation can happen when a particular symbol is defined under a condition.

lambda (n) { if (<= n 1) (trans x 1) println (+ n x) }

With this example, the symbol `x` is a free variable if the argument `n` is greater than 1. While this mechanism can be powerful, extreme caution should be made when using such feature. Note also that many other language do not allow this kind of behavior. That kind of restriction is primarily driven by the need to have a language with `static binding`. The bad news is that it is impossible to write a compiler with dynamic symbol binding.

## Functional objects

Everything is an object. As a consequence, an object can be manipulated, even if it is lexical element, a symbol or a closure.

### Lexical and qualified names

The basic forms elements are the lexical and qualified names. Lexical and qualified names are constructed by the parser. Although the evaluation process make that lexical object transparent, it is possible to manipulate them directly.

(axi) const sym (protect lex) (axi) println (sym:repr) Lexical

In this example, the `protect` reserved keyword is used to avoid the evaluation of the lexical object named `lex`. Therefore the symbol `sym` refers to a lexical object. Since a lexical -- and a qualified -- object is a also a literal object, the `println` reserved function will work and print the object name. In fact, a literal object provides the `to-string` method that returns the string representation of a literal object.

(axi) const sym (protect lex) (axi) println (sym:to-string) lex

### Symbol and argument access

Each nameset maintains a table of symbols. A symbol is a binding between a name and an object. Eventually, the symbol carries the `const` flag. During the lexical evaluation process, the lexical object tries to find an object in the nameset hierarchy. Such object can be either a symbol or an argument. Again, this process is transparent, but can be controlled manually. Both lexical and qualified named object have the `map` method that returns the first object associated in the nameset hierarchy.

(axi) const obj 0 (axi) const lex (protect obj) (axi) const sym (lex:map) (axi) println (sym:repr) Symbol

A symbol is also a literal object, so the `to-string` and `to-literal` methods will return the symbol name. Symbol methods are provided to access or modify the symbol values. It is also possible to change the `const` symbol flag with the `set-const` method.

(axi) println (sym:get-const) true (axi) println (sym:get-object) 0 (axi) sym:set-object true (axi) println (sym:get-object) true

A symbol name cannot be modified, since the name must be synchronized with the nameset association. On the other hand, a symbol can be explicitly constructed. As any object, the `=` operator can be used to assign a symbol value. The operator will behaves like the `set-object` method.

(axi) const sym (Symbol "symbol") (axi) println sym symbol (axi) sym:= 0 (axi) println (eval sym) 0

### Closure

As an object, the `Closure` can be manipulated outside the traditional declarative way. A closure is a special object that holds an argument list, a set of closed variables and a form to execute. The mechanic of a closure evaluation has been described earlier. What we are interested here is the ability to manipulate a closure as an object and eventually modify it. Note that by default a closure is constructed as a lambda expression. With a boolean argument set to true the same result is obtained. With false, a gamma expression is created.

(axi) const f (Closure) (axi) println (closure-p f) true

This example creates an empty closure. The default closure is equivalent to the `trans f nil nil`. The same can be obtained with `const f (Closure true)`. For a gamma expression, the following forms are equivalent, `const f (Closure false)` and `const f nil nil`. Remember that it is `trans` and `const` that differentiate between a lambda and a gamma expression. Once the closure object is defined, the `set-form` method can be used to bind a form.

# the simple way trans f nil (println "hello world") # the complex way const f (Closure) f:set-form (protect (println "hello world"))

There are numerous situations where it is desirable to mute dynamically a closure expression. The simplest one is the closure that mute itself based on some context. With the use of `self`, a new form can be set to the one that is executed. Another use is a mechanism call advice, where some new computation are inserted prior the closure execution. Note that appending to a closure can lead to some strange results if the existing closure expression uses return special forms. In a multi-threaded environment, the ability to change a closure expression is particularly handy. For example a special thread could be used to monitor some context. When a particular situation develops, that threads might trigger some closure expression changes. Note that changing a closure expression does not affect the one that is executed. If such change occurs during a recursive call, that change is seen only at the next call.