我最近开始阅读Paul Grahams的'On Lisp',并学习学习clojure,所以这里可能有一些非常明显的错误,但我看不出来:(显然是一个项目的欧拉问题)< / p>
(ns net.projecteuler.problem31)
(def paths (ref #{}))
; apply fun to all elements of coll for which pred-fun returns true
(defn apply-if [pred-fun fun coll]
(apply fun (filter pred-fun coll)))
(defn make-combination-counter [coin-values]
(fn recurse
([sum] (recurse sum 0 '()))
([max-sum current-sum coin-path]
(if (= max-sum current-sum)
; if we've recursed to the bottom, add current path to paths
(dosync (ref-set paths (conj @paths (sort coin-path))))
; else go on recursing
(apply-if (fn [x] (<= (+ current-sum x) max-sum))
(fn [x] (recurse max-sum (+ x current-sum) (cons x coin-path)))
coin-values)))))
(def count-currency-combinations (make-combination-counter '(1 2 5 10 20 50 100 200)))
(count-currency-combinations 200)
当我在REPL中运行最后一行时,我收到错误:
<#CompilerException java.lang.IllegalArgumentException: Wrong number of args passed to: problem31$eval--25$make-combination-counter--27$recurse--29$fn (NO_SOURCE_FILE:0)>
除了错误所在的问题之外,更有趣的问题是:如何调试这个问题?错误消息不是很有帮助,我没有找到一个很好的方法来单步执行clojure代码,每次遇到问题时我都无法真正询问堆栈溢出。
答案 0 :(得分:13)
可能会让您的生活更轻松的三个提示:
Wrong number of args passed to: problem31$eval--25$make-combination-counter--27$recurse--29$fn (NO_SOURCE_FILE:0)>
告诉你大概发生错误的地方:$fn
最后那里意味着匿名函数,它告诉你它是在recurse里面声明的,它是在make-combination-counter
内声明的。有两种匿名函数可供选择。
如果您将源代码保存在文件中并将其作为脚本执行,它将为您提供包含文件中行号的完整堆栈跟踪。
at net.projecteuler.problem31$apply_if__9.invoke(problem31.clj:7)
注意你也可以通过检查* e例如:(。stackTrace * e)检查REPL中的最后一个异常和堆栈跟踪。堆栈跟踪起初非常艰巨,因为它会抛出所有Java内部。您需要学会忽略它们,只需查找引用代码的行。这种情况非常简单,因为它们都以net.projecteuler
您可以命名匿名函数以帮助更快地识别它们:
(fn check-max [x] (<= (+ current-sum x) max-sum))
在您使用所有这些信息的情况下,您可以看到apply-if正在传递单个参数函数作为乐趣。申请这样做(f [1 2 3]) - &gt; (f 1 2 3)。从你的评论你想要的是地图。 (地图f [1 2 3]) - &gt; (列表(f 1)(f 2)(f 3))。当我用apply
替换map
时,该程序似乎有效。
最后,如果你想检查值,你可能想要查看clojure-contrib.logging
,它有一些帮助这种效果。有一个间谍宏允许你包装一个表达式,它将返回完全相同的表达式,因此它不会影响你的函数的结果,但会打印出EXPR = VALUE
,这可以很方便。同样在该组织中,各种人都发布了完整的跟踪解决方案。总是有可靠的println
。但这里的关键技能是能够确切地确定爆炸的是什么。一旦你知道通常清楚为什么,但有时候当你无法确定输入是什么时需要打印输出。
答案 1 :(得分:2)
虽然它看起来像我没有REPL:
(defn apply-if [pred-fun fun coll]
(apply fun (filter pred-fun coll)))
采用 '(1 2 3 4 5)
之类的列表过滤其中一些 '(1 3 5)
然后创建一个函数调用,如(fun 1 3 5)
看起来它被称为 (apply-if (fn [x]
,其函数想要接收一个数字列表作为单个参数。
您可以将apply-if函数更改为只调用fun(不带apply),或者可以更改对它的调用以获取一个带有任意数量参数的函数。