Macros¶
Macros are the core of M’s higher level abstractions; they allow you to use information from the compiler to transform expressions and create new semantics. To do this, M treats its own structure as a primitive type, and allows the definition of functions which operate on it.
Macro Application¶
Macros are applied just like functions, but instead of operating on the values of their arguments, they operate on the expressions of their arguments.
# The identity function defined using the defn macro
(defn (id x) x)
Creating Expressions¶
Quote expressions are of the form (quote <expr>)
, where expr
is the
expression to evaluate to. Quote allows the creation of static expressions which
can be manipulated by other functions.
# The expression representing def
(quote def)
# The expression representing (fn x x)
(quote (fn x x))
Combining Expressions¶
Expressions can be combined by applying them to other expressions. The application of two expressions is equivalent to the expression representing their application.
# The expression representing (fn x x)
((quote fn) qx qx)
(def qx (quote x))
Transforming Expressions¶
Macros are of the form (fm <args> <val>)
, where where args
is a list of
argument names and val
is the value of the function macro. When applied to
an expression, a macro quotes that expression and transforms it.
# A macro similar to defn
(def deffn
(fm [name args value]
((quote def) name
((quote fn) args value))))
# The identity function defined using the deffn macro
(deffn id [x] x)
Currying¶
Internally, macros are not curried, as they are required to return expressions rather than functions. However, they can still be treated like they are curried, and will work as expected.
# Defines inc with currying
((def inc) (fn x (add 1 x)))
# Equivalent to the above
((defn (inc x)) (add 1 x))