Special Forms

Special forms are pseudo-functions handled directly by the evaluator. They cannot be extended or altered.

Sequence Forms

There are three sequence special forms: begin, and and or. They all take a sequence of expressions and start to evaluate them, one by one. They differ in how many of the expressions they evaluate, what they return and what they return if no expressions are passed.

begin ...
and ...
or ...

begin

begin evaluates all of the expressions and returns the value of the last expression.

This is the normal block of code behaviour.

If no expressions are passed, begin returns #<void>.

and

and evaluates all of the expressions unless an expression returns #f at which point and also returns #f. The remaining expressions are not evaluated.

If all of the expression return a true value then and returns the value of the last expression.

If no expressions are passed, and returns #t.

or

or evaluates all of the expressions until an expression returns a true value and or returns that value. The remaining expressions are not evaluated.

If all of the expressions return #f then or returns #f.

If no expressions are passed, or returns #f.

not

The not special form is used to inverted the sense of a boolean.

There is a function variant, not/function, for where a function is required.

escape

The escape special form is used to prevent the reader implementing operators. The default reader escape character is \.

escape e
\e

escape continues evaluation with its argument.

For example, the infix operator + expects numbers as arguments so we might make a mis-type before escaping it:

Idio> apply + 1 2 3
...:^rt-parameter-type-error:bad parameter type: '#<PRIM apply>' a primitive is not a number
...
#<unspec>
Idio> apply \+ 1 2 3
6

quote

The quote special form is used to prevent the evaluator evaluating its argument. The default reader quote character is '.

quote e
'e

quote returns its argument unevaluated.

For example, any parenthesised list is considered a function call so we need to quote any literal lists:

Idio> printf "a list %s\n" (1 2 3)
...:^rt-function-error:cannot invoke constant type: detail (1)
...
Idio> printf "a list %s\n" '(1 2 3)
a list (1 2 3)
#<unspec>

quasiquote

The quasiquote special form is the basis for expanding templates.

#T{ ... }

function/name

The function/name special form is used to return a function value, commonly called a closure.

function/name name formals [docstr] body

name is the name to be associated with the function.

formals declares the parameters for the closure and arguments passed to the function are available through the named parameters within the body of the function.

formals takes several forms, see closure parameters and the extended forms in function*/name.

The optional docstr allows the user to describe their function. This text will be used in help output as well as used to generate documentation like this. It should take the form of reStructuredText targeting the Sphinx documentation system.

body is a single expression although commonly a block is used as a synonym for the begin sequence special form.

function/name exists largely because debugging with anonymous functions becomes difficult especially when that anonymity exists only because of the deliberate enforcement of anonymity in the evaluator.

(define (foo a b) ...)

was rewritten to:

(define foo (function a b) ...)

but can now be rewritten to:

(define foo (function/name foo a b) ...)

which keeps the normal form and also ensures the name of the function value is carried through.

function

The function special form is used to return a function value, commonly called a closure.

function formals [docstr] body

function only differs from function/name in the absence of a name. function is a simple wrapper to function/name passing (gensym 'anon) as the function’s name.

function+

The function+ special form is used to extend the current function’s argument frame. It appears when a function’s body is rewritten to a normal form.

Users are not expected to use this special form.

if

The if special form is the fundamental test and branch mechanism.

if condition consequent alternative

If the expression condition evaluates to true then evaluate consequent otherwise evaluate alternative.

Whichever of consequent or alternative is evaluated, its result is the value returned by if.

If condition evaluates to #f and there is no alternative then if returns #<void>.

cond

The cond special form is an abstraction of the if Special Form. It is equivalent to many languages’ if ... elif ... elif ... else ....

cond clauses

clauses is a list of clauses where each clause can take the form:

  • (condition ...)

    If the expression condition evaluates to true then evaluate returning its value as the value from cond.

  • (condition => f)

    If the expression condition evaluates to true then call the function f with the result of condition and return the result of f as the value from cond.

    This is the anaphoric if expression, roughly equivalent to:

    it := condition
    if it {
      f it
    }

    where condition is evaluated and the result recorded. If the result was true then call f with the result as an argument.

  • (else ...)

    Evaluate returning its value as the value from cond.

    The else clause can only appear as the last clause

If no clauses satisfy and there is no else clause, cond returns #<void>.

set!

The set! special form modifies memory, hence the ! in the name. It has an = synonym and an = reader operator.

set! var value
= var value
var = value

Note

Technically, set! doesn’t modify any value but changes a reference to point to a different value.

From a user perspective, the variable has a different value.

define-template

The define-template special form is used to create templates.

define-infix-operator

The define-infix-operator special form is used to create reader operators.

define-postfix-operator

The define-postfix-operator special form is used to create reader operators.

define

The define special form is used to create lexically scoped references between symbols, symbolic names, aka identifiers, and values. It has an := synonym and a := reader operator.

define var value
:= var value
var := value

The base form of define is define var value and creates a reference from var to value.

A second form is for defining functions: define (name formals) body.

This is rewritten into the base form as: define name (function/name name formals body) thus creating a reference from name to a function value.

:*

The :* special form is used to create dynamically scoped references between symbols, symbolic names, aka identifiers, and values which will subsequently become environment variables when an external command is executed. It has a :* reader operator.

:* var value
var :* value

environ-let

The environ-let special form is used to evaluate an expression in the context of a dynamically scoped environment variable.

environ-let (var expr) body

environ-unset

The environ-unset special form is used to evaluate an expression in the context of the absence of a dynamically scoped environment variable.

environ-unset var body

:~

The :~ special form is used to create dynamically scoped references between symbols, symbolic names, aka identifiers, and values. It has a :~ reader operator.

:~ var value
var :~ value

dynamic

The dynamic special form is used to access dynamically scoped variables.

There is normally no need to use this as the evaluator should figure our the variable is referencing a dynamic value and create the code accordingly.

dynamic-let

The dynamic-let special form is used to evaluate an expression in the context of a dynamically scoped variable.

dynamic-let (var expr) body

dynamic-unset

The dynamic-unset special form is used to evaluate an expression in the context of the absence of a dynamically scoped variable.

dynamic-unset var body

:$

The :$ special form is used to create lexically scoped references between symbols, symbolic names, aka identifiers, and computed values. It has a :$ reader operator.

:$ var getter
:$ var getter setter
:$ var #n setter
var :$ getter
var :$ getter setter
var :$ #n setter

Here, getter and setter are functions of no args and one arg, respectively, which retrieve or set some, usually, volatile value.

The value of variable SECONDS when evaluated returns the number of seconds the program has been running for. It has no associated setter so trying to give it a value is an error.

block

The block special form is largely a synonym for the begin sequencing special form but it does create a new lexical context.

Variables created within a block are not accessible outside the block.

Amongst other things this allows for the creation of privately scoped variables.

trap

The trap special form is used to set in place a handler for a condition type or types for the evaluation of some body.

trap condition handler body
trap (conditions) handler body

Here, if a condition is raised during the execution of body that is one of the types in conditions or a descendent thereof then handler is run.

handler can choose to:

  • return a value on behalf of the erroring function by simply returning a value

  • can raise the condition to a previously established handler

See Condition Handlers for further information.

include

The include special form is used by the evaluator to pause, load another file and then resume processing the current file.

Note

The C defined include special form uses the C primitive load function not any redefinition.

The Idio defined include special form simply opens the file and evaluates each expression.

include filename

Last built at 2024-09-16T06:10:45Z+0000 from 62cca4c (dev) for Idio 0.3.b.6