Joseph Yourine
Joseph Yourine

Reputation: 1331

Clojure :why does this macro do not work?

I'm exploring macros with basic examples and I do not understand how it works.

This :

(defmacro evalf [f v]
  (f v))
(evalf + 2)

does not work.

I tried :

(defmacro evalf [f v]
  '(f v))
(evalf + 2)

no luck...

I do not understand other syntaxes : ~ ~@ and so on but they does not work either. I see that symbol f is not pointing on + but I do not know to say "take the value of f which is +".

Can you make it clearer ? Thanks in advance

Upvotes: 1

Views: 109

Answers (2)

Thumbnail
Thumbnail

Reputation: 13473

Try

(defmacro evalf [f v]
  (list f v))

(evalf (partial * 2) 66); 132

In the call of evalf

  • the arguments pass unevaluated as forms (partial * 2) and 66;
  • the body of the macro yields the expression (list '(partial * 2) '66);
    • which evaluates to the form ((partial * 2) 66)
    • which, returned from the macro, evaluates to 132.

An alternative, using syntax quoting, is

(defmacro evalf [f v]
  `(~f ~v))

Upvotes: 4

leetwinski
leetwinski

Reputation: 17859

Depending on what do you want to do there are two variants:

First one (the one you probably want) is:

(defmacro evalf [f v] `(~f ~v))

or

(defmacro evalf [f v] (list f v))

Both of them do the same thing: generate the s-expression you need. With this one (evalf + 10) would be expanded to (+ 10) in compile-time, and then successfully evaluated in runtime.

Second one is this:

(defmacro evalf [f v] ((resolve f) v))

Now the function f would be called at compile-time, so macro would be expanded to the result: 10

Your variant with (f v) failed silently, because when you call (evalf + 10), the + here is just a plain symbol, not a reference to the function from macro's point of view, so it tries to call ('+ 10), since the symbol in clojure has function's semantics, it is totally correct syntax, but this call produces nil. (the example of symbol call: ('+ {'+ 10}) => 10) So if you want to get the function, named as this symbol, you will have to resolve it, as in my second example.

And the variant with '(f v) just expands to the list of two symbols : 'f and 'v, and then leads to the runtime call ('f 'v) that also returns nil, like the first variant.

Upvotes: 5

Related Questions