我正在使用基本示例探索宏,但我不明白它是如何工作的。
这:
(defmacro evalf [f v]
(f v))
(evalf + 2)
不起作用。
我试过了:
(defmacro evalf [f v]
'(f v))
(evalf + 2)
没有运气......
我不懂其他语法:~~ @等等,但它们也不起作用。我看到符号f没有指向+但是我不知道说"取f的值是+"。
你能说得更清楚吗? 提前致谢
答案 0 :(得分:4)
尝试
(defmacro evalf [f v]
(list f v))
(evalf (partial * 2) 66); 132
致电evalf
(partial * 2)
和66
; (list '(partial * 2) '66)
;
((partial * 2) 66)
132
。使用语法引用的替代方法是
(defmacro evalf [f v]
`(~f ~v))
答案 1 :(得分:4)
根据您的目的,有两种变体:
第一个(你可能想要的那个)是:
(defmacro evalf [f v] `(~f ~v))
或
(defmacro evalf [f v] (list f v))
他们都做同样的事情:生成你需要的s表达式。
有了这个,(evalf + 10)
将在编译时扩展到(+ 10)
,然后在运行时成功评估。
第二个是:
(defmacro evalf [f v] ((resolve f) v))
现在函数f
在编译时将称为,因此宏将扩展为结果:10
(f v)
的变体无声地失败,因为当您致电(evalf + 10)
时,
+
这里只是一个简单的符号,而不是从宏的角度来看函数的引用,因此它试图调用('+ 10)
,因为clojure中的符号具有函数的语义,它是完全正确的语法,但此调用产生nil
。 (符号调用的示例:('+ {'+ 10})
=> 10)因此,如果您想获得名为此符号的函数,则必须解决它,如我的第二个示例所示。
带有'(f v)
的变体只会扩展为两个符号的列表:'f
和'v
,然后导致运行时调用('f 'v)
也返回{{ 1}},就像第一个变种一样。