如何在另一个 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

标签 <q>、<abbr>、<defn>、<ins>、<del> 和 <s> 的正确用法是啥? [关闭]

Clojure:如何在运行时找出函数的arity?

如何在 Python 中模拟装饰器的内部调用

Python 学习第二天

gcc编译选项总结