如何在另一个 defn 中调用一个 defn 函数以及如何在 Clojure 中调试
Posted
技术标签:
【中文标题】如何在另一个 defn 中调用一个 defn 函数以及如何在 Clojure 中调试【英文标题】:How to call one defn function in another defn and how to debugging in Clojure 【发布时间】:2013-11-15 21:09:32 【问题描述】:我在 Clojure 中运行我的程序时遇到问题。我几周前才开始学习 Clojure。所以我不知道调试 Clojure 程序的快速简便的方法。我的 func2 在(adj(a b))
引发异常,如下所示:
ClassCastException java.lang.Long 无法转换为 clojure.lang.IFn 用户/func2。
我不知道它有什么问题。有人可以指出我的编码问题吗?
在func3中,我递归调用func2
,但它抛出:
ArityException 传递给的 args (0) 数量错误:PersistentVector clojure.lan g.AFn.throwArity (AFn.java:437)
func3 有什么问题?谢谢。
(defn adj [value1 value2]
(def result (+ (/ value1 2) (/ value2 2)))
(if (= (mod result 2) 1)
(+ result 1)
result
)
)
(defn func2 [list]
(let [[a b c d] list]
(inc d)
([(adj c a) (adj a b) (adj b c) d]))
)
(defn func3 [list]
(loop [v list r []]
(if(= (v 0) (v 1) (v 2))
(conj list r)
(func3(func2(list)))
))
)
【问题讨论】:
【参考方案1】:这些函数的预期结果是什么?我们可能需要查看一些示例输入和预期结果才能真正为您提供帮助。
这是我清理它们的尝试。我已经注意到我作为 cmets 所做的更改。 func3
最严重的问题在于它是一个无限递归——没有结束条件。什么应该导致它停止工作并返回结果?
(defn adj [value1 value2]
;; don't use def within functions, use let
(let [result (+ (/ value1 2) (/ value2 2))]
(if (= (mod result 2) 1)
(+ result 1)
result)))
(defn func2 [list]
(let [[a b c d] list]
;; The extra parens around this vector were causing it
;; to be called as a function, which I don't think is
;; what you intended:
[(adj c a) (adj a b) (adj b c) d]))
;; This needs an end condition - it's an infinite recursion
(defn func3 [list]
(loop [v list r []]
(if (= (v 0) (v 1) (v 2))
(conj list r)
;; Removed extra parens around list
(func3 (func2 list)))))
我之所以说不要在函数中使用def
,是因为它总是会创建一个全局函数。对于你想要的本地绑定let
。
关于额外的括号,[1 2 3]
和 ([1 2 3])
之间的区别在于前者返回一个包含数字 1、2 和 3 的向量,而后者试图将该向量作为函数调用。 func2
中的文字向量和 func3
中的 list
周围有多余的括号,这会导致异常。
作为一种风格说明,名称list
不是一个好的选择。一方面,它遮蔽了clojure.core/list
,另一方面,您可能正在使用向量而不是列表。使用coll
(用于集合)或s
(用于序列)作为名称会更惯用。
这表明至少还有其他更改。在func3
中,您使用仅向量功能(使用向量作为函数来执行按索引查找),因此更通用(接受其他数据结构)您可以使用vec
转换为向量:
(defn func3 [coll]
(loop [v (vec coll) r []]
(if (= (v 0) (v 1) (v 2))
(conj v r)
(func3 (func2 v)))))
【讨论】:
感谢您的清晰解释和cmets。我似乎喜欢 Clojure,并希望对其进行更多探索。你能推荐一种调试 Clojure 程序的简单方法吗? 我建议在 REPL 工作,从小块开始,然后从那里开始构建。您可以评估单个表达式,然后,一旦您知道它们按预期工作,就将它们组合成一个或多个函数。这样,当某些东西不起作用时,您将确切地知道错误在哪里——在您刚刚尝试评估的表达式中。这种交互式开发风格在包括 Clojure 在内的 Lisps 中非常普遍,对于学习和构建体验非常有用。 您可能已经知道这一点,但函数pst
有时可能会有所帮助。它打印最后一个错误的堆栈跟踪。它是一个 Java 堆栈跟踪,所以它并不漂亮,但有时 Java 堆栈跟踪中有有用的信息。【参考方案2】:
哦,没有必要调试它。我建议你看看 LightTable。
前两个函数很容易修复:
(defn adj [value1 value2]
;(def result (+ (/ value1 2) (/ value2 2))) def creates a global binding in current namespace !!!
(let [result (+ (/ value1 2) (/ value2 2))]
(if
(= (mod result 2) 1)
(inc result)
result)))
(defn func2 [xx]
(let [[a b c d] xx]
[ (adj c a) (adj a b) (adj b c) (inc d)]
))
第三个功能我不清楚。我没有读懂你的意图。我的理解是:“继续将 func2 应用于自身,直到其结果的前三个元素相等。”但我担心这个条件永远不会满足,所以我用一个 true 替换它,以便只看到一个结果而不破坏堆栈。
(defn func3 [xx]
(loop [ v (func2 xx) ]
(if
;(= (v 0) (v 1) (v 2))
true
v
(recur (func2 v))
)))
有用的链接:http://clojure.org/cheatsheet
干杯 -
【讨论】:
以上是关于如何在另一个 defn 中调用一个 defn 函数以及如何在 Clojure 中调试的主要内容,如果未能解决你的问题,请参考以下文章
react native 运行报_DEV_is not defned