|
|
|
|
|
by LandR
2496 days ago
|
|
The above posters point on Homoiconicity is a big one, here is a quick (and silly) example for anyone unfamiliar with the term. Take the following clojure: (+ 1 2)
=> 3
Here the ( ) delimits, a list, and as the blog post says most lists are function calls.
In this case the function is + and it's params are 1 and 2.It means if we do this (1 + 2)
We get an exception that 1 isn't a function...However, we can tell Clojure to treat this code as data by quoting the list using the ' '(1 + 2)
=> (1 + 2)
THis is now a list. Where the first item in the list is a number and second is a symbol + and the last item is a number.WHat if we write a function to swap the first two items in a list? (defn swap [x]
(list (second x) (first x) (last x)))
(swap '(1 + 2))
=> (+ 1 2)
We have to quote the parameter (1 + 2) as clojure evaluates arguments to functions (mostly..), by quoting it we are saying don't evaluate, instead treat it as data.So you can see (+ 1 2)
Looks like Clojure code, even though it's a list.We can eval it: (eval (swap '(1 + 2)))
=> 3
It's inconvienent to have to remember to quote the params and call eval.Up steps macros, macros are evaluated before compile time and don't evaluate their arguments. So we can rewrite swap as a macro (defmacro swap [x]
(list (second x) (first x) (last x)))
Now we can call (swap (1 + 2))
=> 3
This lets us essentially extend the compiler and create DSLs specific to your domain problem. Creating new language constructs is incredibly easy. |
|