Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Treat Clojure macro as a function

Tags:

macros

clojure

How can I cause a Clojure macro to act as a function, so I can pass it as an argument for example? I would expect to have to wrap it somehow.

I would not expect the wrapped version to behave exactly the same as the original macro (differences of call by name vs call by value), but it would be useful in a few cases where this wasn't important.

like image 756
pauldoo Avatar asked Apr 03 '11 19:04

pauldoo


People also ask

What are threading macros in Clojure?

Threading macros, also known as arrow macros, convert nested function calls into a linear flow of function calls, improving readability. In idiomatic Clojure, pure functions transform immutable data structures into a desired output format.

Is Clojure a primitive programming language?

Many core constructs of Clojure are not, in fact, primitives, but are normal macros. Some macros produce simple combinations of primitive forms. For example, when combines if and do: user=> (macroexpand ' (when (pos?

What is a pure function in Clojure?

In idiomatic Clojure, pure functions transform immutable data structures into a desired output format. Consider a function that applies two transformations to a map: transform is an example of a common pattern: it takes a value and applies multiple transformations with each step in the pipeline taking the result of the previous step as its input.

What are threading macros?

Threading macros, also known as arrow macros, convert nested function calls into a linear flow of function calls, improving readability. In idiomatic Clojure, pure functions transform immutable data structures into a desired output format.


2 Answers

If I'm understanding you correctly, you can just wrap it in a function.

Consider this (silly) implementation of a squaring function as a macro:

(defmacro square [x]
  (list * x x))

Passing it directly as an arg won't work, as you know:

user=> (map square [1 2 3 4 5])
java.lang.Exception: Can't take value of a macro: #'user/square (NO_SOURCE_FILE:8)

But wrapping it in a function will do the trick:

user=> (map #(square %) [1 2 3 4 5])
(1 4 9 16 25)

Alternatively (and quite a bit more evil-ly), you could make another macro to do a more generic wrapping:

(defmacro make-fn [m] 
  `(fn [& args#] 
    (eval `(~'~m ~@args#))))

user=> (map (make-fn square) [1 2 3 4 5])
(1 4 9 16 25)

I'd stick with the normal function wrapping, and skip this last hack! :)

like image 160
trptcolin Avatar answered Oct 01 '22 10:10

trptcolin


There is a dangerous, deprecated macro that you should not ever use. :-P

http://clojure.github.com/clojure-contrib/apply-macro-api.html

like image 43
jneira Avatar answered Oct 01 '22 10:10

jneira