2024 Clojure 状态调查! 中分享您的想法。

欢迎!请查阅关于 页面获取更多关于如何使用本站的信息。

0
;;gets a list like (1 + (1 + 2))
;;returns (+ 1 (+ 1 2))
(defmacro infix [expression]
  (letfn [(helper [expression]
               (cond (not (list? expression)) expression
                     (= (count expression) 0) '()
                     (= (count expression) 1)  (recur (first expression))
                     (not (function? (first expression))) (let [a (first expression)
                                                                op (second expression)
                                                                b (nth expression 2)]
                                                                  (recur (cons (list op a b)
                                                                               (drop 3 expression))))
                    :else expression))]
  (helper expression)))

(macroexpand '(infix (1 + 1 * 2 * 4))) ;; => ((+ 1 1) * 2 * 4)
(macroexpand '(infix (((1))))) ;; => 1

第二个 recur 似乎不起作用(在 (not (function? ....))。代码有什么问题?

1 答案

+3

被选为最佳答案
 
最佳答案

我认为这里可能存在几个相关的谓词问题。对于第一个条件,您可能需要使用比 list?(仅适用于列表集合)更广泛的某种东西,也许可以使用像 sequential? 这样的东西来包含序列。我不确定 function? 是什么,但在您的例子中,那些将是符号,所以 symbol? 应该可以工作。我怀疑这就是您当前的问题所在,因为这不是您看到的分支。您可能想在 cond 中添加一个 :else 分支来告诉您何时不匹配。


编辑
谢谢。函数sequential?解决了这个问题,但为什么普通的列表检查没有?
调试后我发现表达式(list? '((+ 1 1) * 2 * 4))不知为何返回了false。
`list?` 文档说明:如果 x 实现了 IPersistentList,则返回 true。

您确定确切的表达式返回了 false,还是在展示一个示例?`list?` 的结果取决于该形式是如何构造的。例如

(list? (cons '(+ 1 1) '(* 2 * 4))) => false
(list? (list '(+ 1 1) * 2 * 4)) => true

第一个原因是`cons`返回的类型是`clojure.lang.Cons`类型。
您是对的,谢谢!我忘记Clojure没有cons单元。
...