Обработать макрос Clojure как функцию

Как заставить макрос Clojure действовать как функцию, поэтому я могу передать его как аргумент, например? Я бы ожидал, что он каким-то образом обернет его.

Я бы не ожидал, что завернутая версия будет вести себя точно так же, как и исходный макрос (различия между вызовами по имени и вызовом по значению), но это было бы полезно в нескольких случаях, когда это не было важно.

Ответы

Ответ 1

Если я правильно понимаю вас, вы можете просто обернуть его в функцию.

Рассмотрим эту (глупую) реализацию функции квадратизации как макроса:

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

Передача непосредственно, поскольку arg не будет работать, как вы знаете:

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

Но обертывание его в функцию сделает трюк:

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

В качестве альтернативы (и немного более злобно) вы можете сделать другой макрос для более общей обертки:

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

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

Я бы придерживался обычной функциональной упаковки и пропустил этот последний взлом!:)

Ответ 3

Для сумасшедшего макроса make-fn, как насчет ниже? Он также должен работать, и, надеюсь, легче понять.

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