Functions and Macros
Function Definition Forms (defn func [arg1 arg2 arg3] (println arg1 arg2 arg3))
Function Definition Forms (defn func [arg1 arg2 arg3] (println arg1 arg2 arg3)) (def func (fn [arg1 arg2 arg3] (println arg1 arg2 arg3)))
Function Definition Forms (defn func [arg1 arg2 arg3] (println arg1 arg2 arg3)) (def func (fn [arg1 arg2 arg3] (println arg1 arg2 arg3))) (def func #(println %1 %2 %3))
Variadic functions Functions can take an arbitrary number of arguments (fn [arg1 arg2 & moreArgs] (printf arg1 arg2 moreArgs)) Functions can take an arbitrary number of arguments The built-in function + does so The moreArgs parameter is a list of the additional arguments Functions can be written to take zero or more arguments with (fn [& moreArgs] (printf arg1 arg2 moreArgs))
Functions with different numbers of arguments (defn func ([x] (println "got one")) ([x y] (println "got two")))
Macros vs. Functions Functions Macros Execute at run time Evaluate all arguments before calling the function Produce values Are first-class values at runtime can be composed can be mapped over containers Execute at compile time Don't evaluate arguments, just pass the code Produce code Do not exist at runtime compose only with other macros (viral) cannot be mapped
Macros are generally discouraged At least, prefer functions over macros
When to use macros? The code must run at compile time You need access to un-evaluated arguments Code must be emitted inline
When to use macros? The code must run at compile time expensive fixed calculations capturing build time / parameters
When to use macros? You need access to un-evaluated arguments this is the most common case short-circuiting logic and / or definition of code (implicit lambdas)
When to use macros? Code must be emitted inline calling logging commands that capture the line number
Macro definition forms (defmacro macro [arg1 arg2 & args] (...) ...)
Macro definition forms (defmacro macro [arg1 arg2 & args] (...) ...) (defmacro macro ([] "no arguments") ([arg1 arg2 & args] (...) ...))
Example Macro: Scheme-style function definition Scheme function definitions look a bit different from those of LISP and Clojure. (define (func arg1 arg2 arg3) ...) as opposed to (defn func [arg1 arg2 arg3] ...)
Example Macro: Scheme-style function definition Let's try to create a macro to emulate this (defmacro define [name-and-args & body] ...)
Example Macro: Scheme-style function definition Let's try to create a macro to emulate this (defmacro define [name-and-args & body] (let [name (first name-and-args) args (rest name-and-args)] (list 'defn name args body))
Example Macro: Scheme-style function definition Let's try to create a macro to emulate this (defmacro define [name-and-args & body] (let [name (first name-and-args) args (rest name-and-args)] (list 'defn name args body)) That's no good! args needs to be a vector!
Example Macro: Scheme-style function definition Let's try to create a macro to emulate this (defmacro define [name-and-args & body] (let [name (first name-and-args) args (rest name-and-args)] (list 'defn name (into [] args) body))
Example Macro: Scheme-style function definition Let's try to create a macro to emulate this (defmacro define [name-and-args & body] (let [name (first name-and-args) args (rest name-and-args)] (list 'defn name (into [] args) body)) Better, but still not quite right. The body is wrapped in an extra set of parentheses!
Example Macro: Scheme-style function definition Let's try to create a macro to emulate this (defmacro define [name-and-args & body] (let [name (first name-and-args) args (rest name-and-args)] (list 'defn name (into [] args) (cons 'do body)))
Syntax quote Rather than explicitly building the lists, it can be cleaner to use a special kind of quoted expression `(symbol ~evaluated-symbol ~@flattened-list)
NOTE: It is denoted by a back-tick rather than a single quote Syntax quote Rather than explicitly building the lists, it can be cleaner to use a special kind of quoted expression `(symbol ~evaluated-symbol ~@flattened-list) NOTE: It is denoted by a back-tick rather than a single quote
NOTE: It is denoted by a back-tick rather than a single quote Syntax quote Rather than explicitly building the lists, it can be cleaner to use a special kind of quoted expression `(symbol ~evaluated-symbol ~@flattened-list) NOTE: It is denoted by a back-tick rather than a single quote ~symbol is replaced by the value associated with the symbol at compile time
Syntax quote Rather than explicitly building the lists, it can be cleaner to use a special kind of quoted expression `(symbol ~evaluated-symbol ~@flattened-list) NOTE: It is denoted by a back-tick rather than a single quote ~symbol is replaced by the value associated with the symbol at compile time ~@symbol splices the contents of the symbol into the surrounding list