我正在尝试编写一个Clojure宏,从简单的中缀符号列表创建前缀符号列表以便进行计算,比如将
上面,我只是用两个
当我执行上述嵌套的宏调用时,我会得到以下错误:
我原本希望递归调用宏可以在整行被评估前处理未评估的中缀列表,但这似乎不起作用。
我相信后面的内部
(2 * 3 + 4 * 2)
转换为(+ (* 2 3) (* 4 2))
(结果返回14)。以下是我的代码:(defmacro infix [op inlist]
(let [[i1 i2 & i3] inlist
last-group? (nil? (second i3))]
(if last-group?
`(if (= ~op ~i2)
(~i2 ~i1 ~(first i3)) ; return unevaluated prefix list
(~i1 ~i2 ~(first i3))) ; return unevaluated infix list
`(if (= ~op ~i2)
; recur with prefix list in i1 position
(infix ~op ~(conj (rest i3) (list i2 i1 (first i3)) ))
; return as list: i1 and i2, recur i3 (probably wrong)
(~i1 ~i2 (infix ~op ~i3))
))))
为了通过使用不同的op
(操作函数)参数递归调用宏来执行运算符优先级:
(infix + (infix * (2 * 3 + 4 * 2)))
上面,我只是用两个
*
和+
来使用它,但最终我希望调用宏以适用于所有(或至少为了this exercise、/ * + -)运算符。当我执行上述嵌套的宏调用时,我会得到以下错误:
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'cbat.ch7.ex2/infix, compiling:(/tmp/form-init4661580047453041691.clj:1:1)
调用宏来处理单个运算符及其列表(例如(infix * (2 * 3 * 4))
)可以按预期工作。如果我使用单个(i1 i2 i3)
列表调用宏,如果op
与i2
不同,则会尝试(可以理解地)返回未计算的带有错误的中缀列表:
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn cbat.ch7.ex2/eval3003 (form-init4661580047453041691.clj:1)
我原本希望递归调用宏可以在整行被评估前处理未评估的中缀列表,但这似乎不起作用。
我相信后面的内部
if
(即(~i1 ~i2 (infix ~op ~i3))
)的else分支是不正确的,我可能只需要内部的中缀调用,但我更关心在评估之前使不同运算符的嵌套宏调用正常工作。 我知道这不是将中缀转换为前缀表示法的常规方法,后来发现了Dijkstra's shunting-yard algorithm,但请问有人能告诉我: 1.是否可能存在这样的嵌套宏调用? 2.我的逻辑是否合理,离解决方案不太远?如果是这样... 3. ...我需要做哪些更改才能让事情正常运行? 我真的专注于学习Clojure,因此任何详细的解释(在可能的情况下)都将受到欢迎。