KRL supports functions as first-class objects. KRL supports only anonymous functions, but they can be given names by binding them to a variable in a declaration. Here's an example:

Code Block | ||||||
---|---|---|---|---|---|---|

| ||||||

add5 = function(x) { x + 5 }; |

...

Functions are statically executed (i.e., free variables are bound in the environment in which they are defined, not the environment in which they are executed) and can be recursive. KRE limits the number of times a function can be called in any given ruleset evaluation to protect against runaway code. The value of the recursion threshold is installation specific. Here's an example of a recursive function in KRL:

Code Block | ||||||
---|---|---|---|---|---|---|

| ||||||

fact = function(n) { (n <= 0) => 1 | n * fact(n-1) } |

This example also shows the syntax for function application (e.g., `fact(n-1)`

). An expression resulting in a function is followed by a possibly empty, parentheses-delimited, comma-separated list of expressions. Function application is applicative-order; the expressions representing the function and the arguments are evaluated and the result of executing the function expression (the operator, or rator) is then applied to the results of the evaluation of the arguments (the operands, or rands). Obviously, the rator operator must be a function.

To see how declarations appear in the body of a function, consider the following example, which uses Newton's method to calculate square roots (Adapted from section 1.1.8 of *Structure and Interpretation of Computer Programs*.):

Code Block | ||||||
---|---|---|---|---|---|---|

language
| ||||||

sqrt = function(x) { average = function(x,y) { (x + y) / 2 }; good_enough = function(guess, x) { v = (guess * guess) - x; v < 0.01 && v > -0.01 }; improve = function(guess, x) { average(guess, (x / guess)) }; sqrt_iter = function(guess, x) { good_enough(guess, x) => guess | sqrt_iter(improve(guess,x), x) }; sqrt_iter(1.0, x) } |

Functions can return functions as values and functions can be passed as the arguments to other functions and operators in KRL. The following example defines a generalized summation function called `sum`

that sums the numbers from `a`

to `b,`

incrementing using the function `inc`

and applying the function `f`

to each term:

Code Block | ||||||
---|---|---|---|---|---|---|

| ||||||

sum = function(f, a, inc, b) { (a > b) => 0 | f(a) + sum(f, inc(a), inc, b) }; |

You can use sum to define a function that sums the cubes from a to b:

Code Block | ||||||
---|---|---|---|---|---|---|

language
| ||||||

plus1 = function(x) { x + 1 }; cube = function(x) { x * x * x }; sum_cubes = function(a, b) { sum(cube, a, plus1, b) } |

As another example, you can define a function that creates incrementor functions. When given a number, it returns a function that increments by that value:

Code Block | ||||||
---|---|---|---|---|---|---|

| ||||||

inc_gen = function(x) { function{ x + n } }; |

Now you use `inc_gen`

to generate other functions:

Code Block | ||||||
---|---|---|---|---|---|---|

| ||||||

plus1 = inc_gen(1); plus25 = inc_gen(25); |

...