[term-lisp] does not support variables, and its functions are rules that describe how to replace a given term with another one.

For example, consider how the booleans are defined:

(true = Bool True)
(false = Bool False)

This means "when you see the term “true”, replace it with the term “Bool True”

term-lisp supports first-class pattern matching. This means that you can have functions that return patterns.

For example, consider how the if expression is defined:

(if (:literal true) a b = a)
(if (:literal false) a b = b)

Here the terms true and false are automatically expanded, so the expressions above are a shorthand for:

(if (:literal (Bool True)) a b = a)
(if (:literal (Bool False)) a b = b)

To prevent unwanted execution, expressions in term-lisp are evaluated lazily i.e. only when they are needed.

What happens if we construct an expression that looks like function application, but the function being applied is not defined? In most languages, this would result in error, but in term-lisp we will create a new datatype/constructor, e.g. the expression Pair foo bar would evaluate to… Pair foo bar i.e. we will save a new object of type Pair, containing the values of foo and bar.