git @ Cat's Eye Technologies Robin / master stdlib / fun.robin
master

Tree @master (Download .tar.gz)

fun.robin @masterraw · history · blame

;'<<SPEC'

<!--
Copyright (c) 2012-2024, Chris Pressey, Cat's Eye Technologies.
This file is distributed under a 2-clause BSD license.  See LICENSES/ dir.
SPDX-License-Identifier: LicenseRef-BSD-2-Clause-X-Robin
-->

### `fun` ###

    -> Tests for functionality "Evaluate Robin Expression (with Small)"

You can define functions with `fun`.  They can be anonymous.

    | ((fun (a) a) (literal whee))
    = whee

Function have "closure" behavior; that is, bindings in force when a
function is defined will still be in force when the function is applied,
even if they are no longer lexically in scope.

    | ((let
    |    ((a (literal (hi)))
    |     (f (fun (x) (list x a))))
    |   f) (literal oh))
    = (oh (hi))

Functions can take functions.

    | (let
    |   ((apply (fun (x) (x (literal a)))))
    |   (apply (fun (r) (list r))))
    = (a)

Functions can return functions.

    | (let
    |   ((mk (fun (x) (fun (y) (prepend y x))))
    |    (mk2 (mk (literal (vindaloo)))))
    |   (mk2 (literal chicken)))
    = (chicken vindaloo)

Arguments to functions shadow any other bindings in effect.

    | (let
    |   ((a (literal a))
    |    (b (fun (a) (list a a))))
    |   (b 7))
    = (7 7)

If a function is never called, its contents are not
evaluated.

    | (let
    |   ((b (fun (a) (glerp a))))
    |   7)
    = 7

A function may have no arguments at all.

    | ((fun () 7))
    = 7

But, a function must have exactly both a body and a list of formal arguments.
Otherwise, an abort value will be produced.

    | ((fun ()))
    ? abort

    | ((fun))
    ? abort

    | ((fun (a) a a))
    ? abort

An `illegal-arguments` abort will be produced if not enough arguments are
supplied to a function call.

    | ((fun (a b) (glerp b a))
    |   (prepend 1 ()))
    ? abort (illegal-arguments

An `illegal-arguments` abort will be produced if too many arguments are
supplied to a function call.

    | ((fun (a b) (glerp b a))
    |   1 (prepend 2 ()) 3)
    ? abort (illegal-arguments

`fun` is basically equivalent to Scheme's `lambda`.

'<<SPEC'

(define fun (fexpr (args env)
  (bind extend-with-args (fexpr (args env)
    (bind-args (self env-to-extend formals actuals env-for-actuals) args env
      (if (equal? formals ())
        (if (equal? actuals ())
          env-to-extend
          (abort (list (literal illegal-arguments) (head (tail (tail args))))))
        (if (equal? actuals ())
          (abort (list (literal illegal-arguments) (head (tail (tail args)))))
          (let (
              (formal (head formals))
              (actual (head actuals))
              (rest-formals (tail formals))
              (rest-actuals (tail actuals))
              (evaled-actual (eval env-for-actuals actual))
              (binding (list formal evaled-actual))
              (extended-env (prepend binding env-to-extend))
            )
            (self self extended-env rest-formals rest-actuals env-for-actuals))))))
  (fexpr (iargs ienv)
    (bind extended-env (extend-with-args extend-with-args env (head args) iargs ienv)
      (eval extended-env (head (tail args))))))))