View Source Document

choose.robin

;'<<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
-->

### `choose` ###

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

`choose` performs a series of tests and evaluates to the expression
associated with the test that passes.

    | (choose (#t (literal hi)) (else (literal lo)))
    = hi

    | (choose (#f (literal hi)) (#t (literal med)) (else (literal lo)))
    = med

    | (choose (#f (literal hi)) (#f (literal med)) (else (literal lo)))
    = lo

`choose` can have zero tests before the `else`.

    | (choose (else (literal woo)))
    = woo

`choose` does require an `else` branch, or else an abort value will be
produced.

    | (choose (#f (literal hi)) (#f (literal med)))
    ? abort

    | (choose)
    ? abort

Each branch of a `choose` needs to be a two-element list, or else an
abort value will be produced.

    | (choose (#t) (else (literal lo)))
    ? abort

    | (choose (#f 66) (else))
    ? abort

Bindings can be seen inside each of the branches, and inside the `else`.

    | (bind n (literal hi) (choose (#t n) (else (literal lo))))
    = hi

    | (bind n (literal hi) (choose (#f (literal lo)) (else n)))
    = hi

`choose` is basically equivalent to Scheme's `cond`.

'<<SPEC'

(define choose (fexpr (args env)
  (bind choose-r (fexpr (iargs ienv)
    (bind self (eval ienv (head iargs))
      (bind items (eval ienv (head (tail iargs)))
        (bind branch (head items)
          (bind test (head branch)
            (bind then (head (tail branch))
              (if (equal? test (literal else))
                (eval env then)
                (if (eval env test)
                  (eval env then)
                  (self self (tail items))))))))))
    (choose-r choose-r args))))