我正在研究一个Clojure算法来解决这里提出的问题:http://spin.atomicobject.com/2011/05/31/use-clojure-to-move-drugs-a-programming-challenge/我遇到了打嗝。
我正在使用递归算法(也许不是开头的正确选择),走过一个按照从最高到最低的重量比排序的“玩偶”结构的向量。相关代码是:
(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向量返回到调用位置时,我收到以下错误:
CompilerException clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentVector,compiling:(drugmover\tests.clj:83)
第82-83行:
(def empty-dolls {})
(def designated-dolls (get-carryable-dolls sorted-values empty-dolls))
我对编译器错误中可能导致问题的原因感到困惑,并且由于Clojure似乎更喜欢简单的错误消息而不是堆栈跟踪(或者至少是Clooj中的REPL功能),我在失去了如何解决它。如果有人有任何建议,我将非常感谢他们!
提前致谢。
修改
我已经使用答案和评论中的建议修改了代码,并提供了一些注释来帮助说明正在进行的流控制。希望通过说明我的想法,有人能够让我知道我哪里出错了。
答案 0 :(得分:4)
以下代码包含您在其他答案和其他答案中已收到的大部分建议,即:
loop
/ let
代替def
进行本地名称绑定seq
检查空列表carryable-dolls
seq的不必要检查如果没有你所拥有的辅助函数的定义(例如will-fit?
),我无法测试它,但至少应修复一些问题(并以更易读的形式提供代码):< / p>
(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)))))
以下是利用标准reduce
函数的代码的完整重构,并定义了一个函数,该函数提供核心决策逻辑,是否必须在结果中包含玩偶:
(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))
答案 1 :(得分:3)
在这段代码中有太多方法,它们会导致问题。我强烈建议您按照其他人的方式格式化您的代码,这样可以轻松突出这样的错误。我甚至猜不出你要做什么,所以我不能重写整个片段,但需要注意的是if
的语法是:
(if test then else)
在这些事情中不允许额外的任何事情:例如,(if true 1 2)
很好,但是(if (true) 1 2)
会尝试将true
作为函数调用,并且因为它是布尔值而失败。如果您想要将表达式“分组”在一起并评估其副作用,则需要(do expr1 expr2)
,而不是(expr1 expr2)
。
答案 2 :(得分:3)
您的if
代码周围有额外的问题,这就是导致该错误的原因:
下面的代码会产生相同的错误,因为它有额外的parens(在if中调用else部分来创建向量时的情况相同:
((vec {:a 10 :b 100}))
尝试在REPL中执行此操作,您将看到相同的异常:
java.lang.IllegalArgumentException: Wrong number of args (0) passed to: PersistentVector (NO_SOURCE_FILE:0)