I'm new in learning and working with clojure so I've got a basic question on macros in clojure. I didn't find a case where you really need macros so I'm wondering if there is a real case where only a macro and no normal function or multimethod solves your problem.
Can someone show a simple example for this?
I think I didn't understand the concept of macros in clojure.
Clojure macros take literal code whereas functions take evaluated code. In turn, macros are useful when you need to manipulate literal code. Literal code and evaluated code are equivalent except for two (very important) instances: symbols and expressions (maps, vectors, sets, strings, keywords, numbers, booleans, etcetera, will all "evalute to themselves").
user=> 1 ;evaluates to itself
1
user=> "abc" ;evaluates to itself
"abc"
user=> :xyz ;evaluates to itself
:xyz
user=> [1 "abc" :xyz] ;evaluates to itself
[1 "abc" :xyz]
As opposed to:
user=> (+ 1 2) ;an expression evaluates to not itself
3
user=> Math/PI ;a symbol evaluates to not itself
3.141592653589793
user=> + ;another example, a little weirder
#<core$_PLUS_ clojure.core$_PLUS_#417ffb28>
Let's say you wanted to create some-fn-or-macro to behave like this:
user=> (some-fn-or-macro (get {:a 10 :b 20} :a))
"(get {:a 10 :b 20} :a)"
user=> (some-fn-or-macro +)
"+"
You will not be able to do this with a function. Try it:
user=> (defn some-fn-or-macro [expr] (str expr))
#'user/some-fn-or-macro
user=> (some-fn-or-macro (get {:a 10 :b 20} :a))
"10"
What happened here? The argument to some-fn-or-macro (namely expr) got evaluated prior to being string-ized. However, if all we do is change the definition from a function to a macro, everything will be great:
user=> (defmacro some-fn-or-macro [expr] (str expr))
#'user/some-fn-or-macro
user=> (some-fn-or-macro (get {:a 10 :b 20} :a))
"(get {:a 10 :b 20} :a)"
That being said, if we take the original function definition again, and simply quote the argument on invocation, that also works:
user=> (defn some-fn-or-macro [expr] (str expr))
#'user/some-fn-or-macro
user=> (some-fn-or-macro '(get {:a 10 :b 20} :a))
"(get {:a 10 :b 20} :a)"
So you only ever need to write a macro if your use-case demands that arguments remain literal/unevaluated. If you have control over how your tool is used (which I'm guessing is always marginally true), you can decide to develop a function, and instruct users to quote arguments as necessary.
***Note: How I've used macros above might leave you in the dark about one extremely important fact of macros: their output gets evaluated. For example:
user=> (defmacro example-macro [] '(+ 1 2))
#'user/example-macro
user=> (example-macro)
3
You might think this is odd. There are a couple ways to make sense of it. Macros expect to take source code as input, so it's only natural that they'd give source code as output--and source code demands evaluation at some point. Actually, I tend to think of the difference between macros and functions as "shifted evaluation"--evaluation happens either "before" invocation, on the arguments (for functions); or "after" invocation, on the output (for macros).
Important thing here is that macro does not evaluate its arguments and can be used for arbitrary transformation of source code.
Most basic examples of macros would be when and when-not macros:
(defmacro when
"Evaluates test. If logical true, evaluates body in an implicit do."
[test & body]
`(if ~test (do ~#body)))
(defmacro when-not
"Evaluates test. If logical false, evaluates body in an implicit do."
[test & body]
`(if test nil (do ~#body)))
Function won't work here, as it has to evaluate all its arguments before execution.
P.S. If you're interested in the topic and want to know more, see also this my answer. It is about Common Lisp, but it could be useful for you too. I also give a link to a cool Paul Graham's article at the end of the answer.
P.S.S If you want an example of a new useful macro, I would like to comment something of Paul Graham here:
It would be convenient here if I could give an example of a powerful macro, and say there! how about that? But if I did, it would just look like gibberish to someone who didn't know Lisp; there isn't room here to explain everything you'd need to know to understand what it meant.
Related
Imagine the following code to dynamically create a macro:
(def a (list '+ 1 2))
(def b (list '- 10 5))
(def c (list '/ 22 2))
(defmacro gg [h]
(let [k# `~h]
k#))
The intent is to pass a vector of symbols to a macro, do some evaluation on each element of the vector such that it returns a nice macro-esque form, then have the macro combine them into a nice macro and evaluate it. The above example works all except the actual evaluation.
When I run it I get:
(gg [a b c])
=> [(+ 1 2) (- 10 5) (/ 22 2)]
What is the secret to passing a symbol that is a list of symbols and getting a macro to evaluate them? I have tried lots of combinations of quoting and have yet to hit the right one.
The real purpose of this question is to build an Archimedes Ogre query based on a definition of a path through the graph. If someone has an example of that, I would be grateful.
EDIT:
(defmacro gg2 [h]
`(do ~#(map identity h)))
(macroexpand '(gg2 [a b c]))
=> (do a b c)
(gg2 [a b c])
=> (/ 22 2)
I was hoping to get 11 rather than the form.
You don't need a macro. Macros don't do what you're looking for here. What you are looking for is eval.
(def a '/)
(def b 22)
(def c 2)
(eval (list* [a b c]))
=> 11
Of course, you can write a macro which expands into (eval (list* ...)) if you want. It could just as well be a function though.
This is a very common mistake when starting out with macros; trying to write a macro which depends on the run-time value of its arguments. Macros run at compile-time, and generally the values of the symbols which you pass to a macro are not yet available when the macro is expanded.
About the use of eval, some cautions are in order. No one said it better than Paul Graham:
Generally it is not a good idea to call eval at runtime, for two reasons:
It’s inefficient: eval is handed a raw list, and either has to compile it on the spot, or evaluate it in an interpreter. Either way is slower than compiling the code beforehand, and just calling it.
It’s less powerful, because the expression is evaluated with no lexical context. Among other things, this means that you can’t refer to ordinary variables visible outside the expression being evaluated.
Usually, calling eval explicitly is like buying something in an airport gift-shop. Having waited till the last moment, you have to pay high prices for a limited selection of second-rate goods.
Apologies for any mistaken terminology--I'm quite new to computer science, and I pretty much only know Clojure (but I guess I'd say I know it pretty well).
So, I haven't done a ton of research on this, but I've sometimes found it useful when writing Clojure code to be able to refer to some "intermediate version of whatever data structure I'm in" from within that data structure (a lot like in a let). Quick examples:
=> (self-ish {:a 10
:b (inc (this :a))
:c (count (vals this))})
=> {:a 10, :b 11, :c 3}
=> (self-ish ["a" "b" (reduce str this)])
=> ["a" "b" "ab"]
//Works in any nested bits too
=> (self-ish [1 2 3 [4 5 (first this)] 6 [7 [8 (cons (second this) (nth this 3))]]])
=> [1 2 3 [4 5 1] 6 [7 [8 (2 4 5 1)]]]
The idea is that the structure builds itself up incrementally, and at any stage has the ability to refer to the current intermediate structure as this. Here's the code for my current implementation:
//Random straightforward but helpful definitions
(defn map-entry? [obj]
(instance? clojure.lang.AMapEntry obj))
(def Map clojure.lang.IPersistentMap)
(def Vector clojure.lang.IPersistentVector)
(def List clojure.lang.IPersistentList)
(def Set clojure.lang.IPersistentSet)
(defn append
[x coll]
(if-not coll x
(condp instance? coll
Map (if (empty? x) coll
(assoc coll (first x) (second x)))
Vector (conj coll x)
Set (conj coll x)
List (apply list (concat coll [x]))
(concat coll [x]))))
(defn build-this
[acc-stack acc]
(->> (cons acc acc-stack)
(drop-while list?)
(drop-while (every-pred empty? identity))
(reduce append)))
(defn self-indulge
[acc-stack acc form]
;//Un-comment the following to see it print intermediate stages of processing
#_(println "this:" (build-this acc-stack acc) "\n at:" form)
(append (cond
(coll? form) (reduce (partial self-indulge (cons acc acc-stack))
(if (map-entry? form) []
(empty form))
form)
(= (quote this) form) (build-this acc-stack acc)
:else form)
acc))
(defmacro self-ish
[form]
(self-indulge () nil form))
The append function appends an item onto a collection and returns the same type of collection. The self-indulge function has a standard reduce-like accumulator, which just builds up elements of form. It also has a accumulator stack, which gets longer every time self-indulge recurs upon itself. The point of this is to keep track of other "higher up" accumulators, so that this will be the entire structure, not just a local piece. The self-ish macro just nicely wraps up self-indulge (which calls itself using partial, so it can't wear the macro pants).
Edit: example use case
To me, this macro is about trying to increase code readability, not truly extending functionality. Where I have found this useful is in cases where I have hand-written structures with partially redundant data--or maybe "dependent" is a better word. It can be easier to read the code and see what different parts of the data structure hold, and it can also be useful if I modify data values in one part of a structure and want that change to be reflected in other parts. For example:
=> (self-ish {:favorite-books (list "Crime and Punishment" "Mrs. Dalloway")
:favorite-things (list* "Ice Cream" "Hammocks" (this :favorite-books)})
=> {:favorite-things ("Ice Cream" "Hammocks" "Crime and Punishment" "Mrs. Dalloway"),
:favorite-books ("Crime and Punishment" "Mrs. Dalloway")}
It could also be useful in times where one might really like to include something baked into the data, as opposed to derived on the fly using some function. These cases are probably much rarer, and I think it would be a bad idea to tangle the data unnecessarily when you could just have nice clean functions manipulating it.
My main questions:
Is this actually useful, or would the ambiguity/complexity incurred be too much? I imagine I'm not alone in wanting/using this type of macro. What are others' experiences here? Do you use something like this? Have you found better workarounds? Are there reasons something like this isn't in any Clojure libraries? Or is there something that I haven't yet seen?
Are there better naming conventions I might use--as opposed to self-ish and this? For example, maybe this is too loaded with OOP meaning, I'm not sure, I am basically only familiar with Clojure.
I am pretty new to computer science, are there accessible and informative resources related to this type of thing--I guess I would call it anonymous self referential (maybe reflexive is a better word?) data structures? I haven't found anything both approachable and informative yet.
Is there a better way to write the self-ish macro? Above, I've included my current version of it, but I can't shake the feeling there may be a simpler way.
I have various questions about what might be the "wisest" implementation details.
Traversal: Should it be breadth first or depth first? If depth first, preorder, postorder, or inorder? Right now, I believe it's depth first preorder, which makes sense to me, but maybe it has some drawbacks I haven't noticed.
Order problems: (See here for a related previous question of mine) Within {} (i.e. maps written by hand) it's impossible to maintain order properly (above 8 map entries) without using array-map or sorted-map--in other words, above 8 map entries, {} usage is unsafe. Maybe instead of hand-written order, the macro could do some fancy magic to process items in some "ideal" order? Or perhaps it would be better to wrap all maps within (array-map ...) instead of the eye-pleasing {}?
//Showing maps with 9 entries failing
=> (self-ish {:a 1
:b (inc (this :a))
:c (inc (this :b))
:d (inc (this :c))
:e (inc (this :d))
:f (inc (this :e))
:g (inc (this :f))
:h (inc (this :g))
:i (inc (this :h))})
=> NullPointerException clojure.lang.Numbers.ops (Numbers.java:942)
//8 works fine
=> (self-ish {:a 1
:b (inc (this :a))
:c (inc (this :b))
:d (inc (this :c))
:e (inc (this :d))
:f (inc (this :e))
:g (inc (this :f))
:h (inc (this :g))})
=> {:h 8, :g 7, :f 6, :e 5, :d 4, :c 3, :b 2, :a 1}
Serial: As I've written it, the macro avoids infinite recursion by dealing with its elements serially, similar to let, but that does produce potentially odd behavior. For example, in my above quick example, (reduce str this) returns "ab" because this is ["a" "b"] at that step. Maybe it would be useful sometimes to create some sort of infinite lazy sequence instead? If so, how might that be implemented?
Map entries: Right now, map entries are treated like vectors, but because of how this could be invoked at any intermediate step, it is totally possible to get a nil value from a key that has "not yet" been assigned a value. That is why in my first quick example, :c ended up mapped to 3--because intermediately there was a nil corresponding to :c, and that got counted as well. Do you think this warrants fixing?
Non-macro utility: It would be trivial to use just self-indulge outside of the macro context, but could this ever be useful?
Thanks for reading, any help is appreciated :)
This approach "feels" a bit wrong to me, though I'm not quite sure why. Maybe I don't like the idea of map construction being dependent on order....
Having said that it's a pretty easy macro to write, you effectively want something that expands to:
(let [this {}
this (assoc this :a 1)
this (assoc this :b (+ (this :a) 3))]
this)
Hence an appropriate macro would be something like (for the map case):
(defmacro self-ish [bindings]
`(let [~'this {}
~#(mapcat
#(do `(~'this (assoc ~'this ~#%)) )
(partition 2 bindings) )]
~'this))
(self-ish [:a 1
:b (+ (this :a) 3)])
=> {:b 4, :a 1}
Note that I'm made the binding form a vector as a map binding form is unordered.
Still not sure how much I like this idiom. My preferred way is usually to define a structure with a let form and give meaningful names to interim calculations e.g.:
(let [meaningful-foo (something)
meaningful-bar (something-else)]
{:foo meaningful-foo
:bar meaningful-bar
:baz (some-calculation meaningful-foo meaningful-bar)})
in scheme this is done with (letrec ...) which lets you refer to the name of the data structure inside the structure itself. so if you want to define your own way of doing this it might make more sense to implement that. you could do it using the tricks with references described in the answers to Is it possible to create circular references in Clojure?
one advantage of letrec is that it has a user-specified name (if your macro is nested then this is shadowed).
[edited to remove comment on types as i don't understand your macro.]
[update] also, you may be interested in the discussion of anaphora in joy of clojure section 8.5.1
I am working on a macro, I am trying to figure out how to avoid expansion of certain forms, take the following and macro for example,
(defmacro and
([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (and ~#next) and#))))
When expanded,
(mexpand-all '(and 1 2 3))
becomes,
(let* [and__973__auto__ 1]
(if and__973__auto__
(let* [and__973__auto__ 2]
(if and__973__auto__ 3 and__973__auto__))
and__973__auto__))
In this case what I need to do is stop let from expanding into let*.
Huh? It's not clear what you mean by "stop" let from expanding. let is a macro defined in clojure.core, which the compiler knows nothing about: it only understands let*. If your macro expanded into a let which (somehow) refused to expand further, it would fail to compile.
If you want to inspect just the output of your macro in isolation, without worrying about recursively expanding it, you should use macroexpand or macroexpand-1 instead of this mexpand-all thing. I don't know where mexpand-all comes from, but when I need something like that I use clojure.walk/macroexpand-all.
Recursive macro-expansion works by repeatedly expanding the form until there is no macro to expand. That means that if you want to recursively expand a macro, but ignore certain forms, you'll have to either code your own custom expander, or find someone else's.
Here's a quick example:
(defn my-expander [form]
(cond (not (list? form)) (mexpand-1 form)
(= (first form) 'let) form
:else (map my-expander (mexpand-1 form))))
Please forgive me if I made any mistakes. I'm much stronger with Scheme and CL than Clojure.
--Edit--
Note that the above function will not expand the subforms of a let statement, either.
Use macroexpand-1 to perform a single level of macro expansion.
After loading your and macro, this expression:
user=> (macroexpand-1 '(and 1 2 3))
Yields:
(clojure.core/let [and__1__auto__ 1] (if and__1__auto__ (clojure.core/and 2 3) and__1__auto__))
I have two macros. The first one takes a symbol as the only parameter (because it's passed to def, which needs a symbol). The second function takes a list of symbols and should call the first with each symbol individually.
(defmacro m1 [s]
'(let [f# ... dynamic function definition ...]
(def ~s f#))
The second macro should take a list of symbols and pass them to the first, but I can't get it to work. The best I could come up with was the following:
(defmacro m2 [symbols]
`(for [s# ~symbols] (eval (read-string (str "(name.of.current.namespace/m1 " s# ")")))))
which forces the s# to be evaluated before it is passed to the first macro. It is also invoked with a list of strings, rather than a list of symbols.
This is useful for a library which I am using for which all of the functions in the library takes the same two first parameters. I am trying to create wrapper functions, in my namespace, for some of the functions, which automatically provides the first two parameter values which are common to all of them.
Any ideas to improve this?
Usually when you ask how to get two macros to cooperate, the answer is to not make them both macros. I think my blog post on macro-writing macros will help clarify. For this particular situation I'd probably combine two suggestions from the comments:
(defmacro build-simpler-functions [& names]
(cons 'do
(for [name names]
`(def ~(symbol (str "simple-" name))
(partial ~name 5 10))))) ; if you always pass 5 and 10
(build-simpler-functions f1 f2)
This expands to
(do
(def simple-f1 (clojure.core/partial f1 5 10))
(def simple-f2 (clojure.core/partial f2 5 10)))
which looks like basically what you want.
Edit: if the args you "always" pass are different for each function, you can do this:
(defmacro build-simpler-functions [& names]
(cons 'do
(for [[name & args] names]
`(def ~(symbol (str "simple-" name))
(partial ~name ~#args)))))
(build-simpler-functions [f1 5 10] [f2 "Yo dawg"]) ; expansion similar to the previous
This question is a based on a limitation of this answer.
If I have a macro that uses splicing unquote like this:
(defmacro instantiate [klass values]
`(new ~klass ~#values))
It will only work if values is a literal sequence or seq-able.
If it is passed a var holding a sequence like:
(def v [1 2 3])
(macroexpand '(instantiate Person v))
Then the output would be an error indicating that v is not a sequence.
Even a function call would be interpreted as a list:
(defn vf [] [1 2 3])
(macroexpand '(instantiate Person (vf)))
user=>(new Person vf)
My question is: Is there any way to use the splicing unquote in Clojure macros in those two cases where the sequence to be spliced isn't a literal?
Macros receive their arguments unevaluated, so the behavior you are seeing is as intended.
Macros are expanded at compile time, not run time. The values of any variables passed into a macro may not be available at compile time, so dirty hacks like using eval will not work in the general case. Don't create macros that require such tricks.
splicing quotes save a lot of time in almost all cases, except when they dont work, then you need to do things the old fashioned way...
(defmacro instantiate [klass values]
`(new ~klass ~#values))
could become
(defmacro instantiate [klass values]
(concat (list 'new klass) (if (seq? values)
values
(list values))))
user=> (macroexpand '(instantiate asdf (1 2 3)))
(new asdf 1 2 3)
user=> (macroexpand '(instantiate asdf 1))
(new asdf 1)