函数打印在clojure中有缺陷吗?
我写了一个宏:函数打印在clojure中有缺陷吗?,clojure,macros,eval,Clojure,Macros,Eval,我写了一个宏: (defmacro te [a b & c] `(print ~(a b c))) 跑 (te print 2 inc 4) 获取错误ClassCastException java.lang.Long无法强制转换为clojure.lang.IFn用户/eval8010(表单-init8519408737285198.clj:1) 我跑 (macroexpand-1 '(te print 2 3 4) ;=> (clojure.core/prin
(defmacro te
[a b & c]
`(print
~(a b c)))
跑
(te print 2 inc 4)
获取错误ClassCastException java.lang.Long无法强制转换为clojure.lang.IFn用户/eval8010(表单-init8519408737285198.clj:1)
我跑
(macroexpand-1 '(te print 2 3 4)
;=> (clojure.core/print (3 4))
它的意思是(打印2(34))
返回(34)
?它的功能print
有缺陷吗
我的clojure版本1.7.0,JVM版本1.8.0_65-b17
更新 好的,这个例子不容易被commit理解 就连我自己也在经营这家公司
(te print 2 inc 4)
user=> (te print 2 inc 4)
;=> 5nil
user=> (macroexpand-1 '(te print 2 inc 4))
;=> (clojure.core/print (inc 4))
它将打印
5
并返回nil
,这意味着(打印2(inc 4))
返回表单(inc 4)
?这与打印
完全无关
它的意思是(打印2(34))
返回(34)
这不是它的意思,这是你问题的根源。它表示“使用第一个参数2
调用函数print
,第二个参数调用(34)
”的值。表达式(3 4)
没有有效值,因为它表示“使用参数4
调用函数3
”,这就是为什么会出现异常:3是一个长(数字),不能作为函数调用(在clojure内部,它不实现IFn函数接口)
顺便说一句,如果我了解您想要实现的目标(我可能错了),您的宏可以很容易地作为函数编写,这通常意味着您应该将其作为函数编写,因为函数更容易处理,并且与其他函数一起工作得更好。请记住,宏的参数在执行宏时没有计算过 被调用 当您像这样调用宏时: (te print 2 inc.4) 这些参数绑定到以下各项:
- 答:
打印
- b:
'2
- c:
(因为宏是可变的,所以超过前两个的任何参数都会被放入 进入”(inc 4)
中的列表)c
打印与函数不是一回事
clojure.core/print
。这是一个宏,所以它是一个未赋值的符号。你正在使用
在本例中,符号本身作为函数,而不是使用引用的函数
用符号来表示
Clojure中的每个符号都是在地图中查找自身的函数。
查找需要两个步骤
参数、键和默认值。在这种情况下,符号打印
正在尝试查找
在2分钟内自动上升。由于2不是映射,它将返回默认值(inc 4)
回想一下,unquote(~
)表示计算表达式并替换结果
输入宏生成的代码
因此编译器计算:('print'2'(inc4))
返回(inc4)
,然后
将其替换为原始表达式
这就是你如何得到(clojure.core/print(inc 4))
试试这个:
(macroexpand-1’(te blarg 2 inc.4))
你甚至可以得到完全相同的结果
尽管blarg
不是Clojure中定义的变量
在你的另一个例子中,另一个答案非常正确。如果宏的第三个参数不是函数,则会出现另一个错误
老实说,我不确定你想完成什么,所以我不确定这是否真的回答了你的问题。但这就是为什么你看到了你所看到的。为什么人们经常认为公共库/框架中存在未在相关组中报告的bug{相反,考虑这一点:表单<代码>(3 4)<代码>在Culjure中意味着什么?(在RePL上对宏的输出进行评估是无关的)。为什么会导致报告错误?为什么错误仍然存在(并且它会)。在用其他东西替换print
之后?我知道,但我想你不明白我的问题的意思。在宏中,~(ab c)可以重新运行一个非零的值吗a
是函数print
它将返回一个表单c
?我想你想问的是:因为`(print inc~(2))
将获得表单(打印3)
,为什么(defmocro打印结果[ab]`(打印~(ab))
和(macroexpand-1'(打印结果inc 2))
将获得(打印零)
?(a2(34)
实际上返回(34)
,不过,a
的值是符号print