将Clojure宏作为函数 [英] Treat Clojure macro as a function

查看:142
本文介绍了将Clojure宏作为函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使一个Clojure宏作为一个函数,所以我可以传递它作为参数的例子?



我不会期望被封装的版本与原始宏的行为完全一样(名称的调用与调用的差异)值),但在一些不重要的情况下会很有用。

解决方案



将平方函数的这个(愚蠢)实现视为一个宏:

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

直接作为参数传递不会工作,因为你知道:

  user = > (map square [1 2 3 4 5])
java.lang.Exception:不能取宏的值:#'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〜@ args#))))

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


b $ b

我会坚持正常的函数包装,并跳过这最后一次黑客! :)


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.

解决方案

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! :)

这篇关于将Clojure宏作为函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆