Clojure returning values from recursive call
我正在研究Clojure算法,以解决此处提出的问题:http://spin.atomicobject.com/2011/05/31/use-clojure-to-move-drugs-a-programming-challenge/而且我已经打h了。
我正在使用一种递归算法(也许不是正确的选择),以遍历"玩偶"结构的矢量,这些矢量按权重从高到低的顺序排序。相关代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | (defn get-carryable-dolls [dolls carryable-dolls] (def doll (first dolls)) ;initializing for use in multiple places (def rest-dolls (rest dolls)) ;initializing for use in multiple places ( if (will-fit? doll (get-weight-sum carryable-dolls)) ( ;will fit ( if (= carryable-dolls {}) (def new-doll-set [doll]) ;First trip, get rid of empty set by initializing new (def new-doll-set (flatten [doll carryable-dolls])) ;otherwise, flatten set into vector of structs ) ;tests to see if we have any more dolls to test, and if so, recurses. Otherwise, should pass the resultant vector ;up the stack. it appears to be the"else" potion of this if statement that is giving me problems. (if (not= () rest-dolls) (get-carryable-dolls rest-dolls new-doll-set) (vec new-dolls)) ) ( ;will not fit ;gets the rest of the dolls, and sends them on without modifying the vector of structs ;it appears to be the"else" potion of this if statement that is giving me problems. (if (not= () rest-dolls) (get-carryable-dolls rest-dolls carryable-dolls) (vec carryable-dolls)) ) ) ) |
该代码正常运行; returnable-dolls包含所需的洋娃娃结构向量,以作为解决方案返回。不幸的是,当我尝试将returnable-dolls向量返回到调用位置时,我收到以下错误:
1 | CompilerException clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentVector,compiling:(drugmover\\tests.clj:83) |
第82-83行读为:
1 2 | (def empty-dolls {}) (def designated-dolls (get-carryable-dolls sorted-values empty-dolls)) |
对于可能导致编译器错误的原因,我感到很困惑,并且由于Clojure似乎更喜欢简洁的错误消息,而不是堆栈跟踪(或至少Clooj中的REPL功能确实如此),因此我处于失去了如何解决它。如果有人有任何建议,我将不胜感激!
预先感谢。
编辑:
我已经用答案和注释中的建议修改方法修改了代码,并提供了一些注释以帮助说明正在进行的流控制。希望通过说明我的想法,有人可以让我知道我要去哪里错了。
以下代码合并了您在其他答案和其他答案中已经收到的大多数建议,即:
- 摆脱多余的(和错误的)括号
- 以更惯用的方式格式化代码
-
使用
loop /let 代替def 进行本地名称绑定 -
使用
seq 检查空列表 -
在添加元素之前,删除不必要的空
carryable-dolls seq检查
如果没有定义您的辅助功能(例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | (defn get-carryable-dolls [dolls carryable-dolls] (loop [doll (first dolls) rest-dolls (rest dolls)] (if (will-fit? doll (get-weight-sum carryable-dolls)) (let [new-doll-set (if (seq carryable-dolls) (cons doll carryable-dolls) [doll])] (if (seq rest-dolls) (recur rest-dolls new-doll-set) (vec new-dolls))) (if (seq rest-dolls) (recur rest-dolls carryable-dolls) (vec carryable-dolls))))) |
以下是对代码的完整重构,该代码利用标准的
1 2 3 4 5 6 7 | (defn add-if-fits [dolls doll] (if (will-fit? doll (get-weighted-sum dolls)) (cons doll carryable-dolls) carryable-dolls)) (defn get-carryable-dolls [dolls carryable-dolls] (reduce add-if-fits carryable-dolls dolls)) |
您在
下面的代码将产生相同的错误,因为它具有额外的括号(如果在调用else部分以创建矢量时,情况与此相同):
1 | ((vec {:a 10 :b 100})) |
尝试在REPL中执行此操作,您将看到相同的异常:
1 | java.lang.IllegalArgumentException: Wrong number of args (0) passed to: PersistentVector (NO_SOURCE_FILE:0) |
此代码中有太多的原因,它们会引起问题。我强烈建议您以其他所有人的方式设置代码格式,这将使这样的错误很容易被发现。我什至猜不到您要做什么,所以我无法重写整个代码段,但需要注意的相关事项是
1 | (if test then else) |
在所有这些情况下都不允许使用多余的括号:例如,