0

我正在研究 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 功能确实如此),我不知道如何要解决这个问题。如果有人有任何建议,我将不胜感激!

提前致谢。

编辑:

我已经用答案和评论中的人建议的修复修改了代码,并提供了一些评论来帮助说明正在进行的流控制。希望通过说明我的想法,有人能够告诉我我哪里出错了。

4

3 回答 3

4

以下代码包含您在其他答案和其他答案中已经收到的大部分建议,即:

  • 去掉多余的(和错误的)括号
  • 以更惯用的方式格式化代码
  • 使用loop/let而不是def本地名称绑定
  • 用于seq检查空列表
  • carryable-dolls在添加元素之前删除对空序列的不必要检查

如果没有您拥有的辅助功能的定义(例如),我无法对其进行测试will-fit?,但至少应该解决几个问题(并使代码以更易读的形式出现):

(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))
于 2012-04-22T11:58:36.610 回答
3

这段代码中有太多的括号,它们会导致问题。我强烈建议您像其他人一样格式化您的代码,这会使这样的错误很容易脱颖而出。我什至无法猜测您要做什么,所以我无法重写整个代码段,但需要注意的相关事项是 for 的语法if是:

(if test then else)

这些东西周围不允许有额外的括号:(if true 1 2)例如,很好,但(if (true) 1 2)会尝试true作为函数调用,并且因为它是布尔值而失败。如果您想将表达式“组合”在一起并评估它们的副作用,您需要(do expr1 expr2),而不是(expr1 expr2).

于 2012-04-22T04:04:29.207 回答
3

您的if代码周围有额外的括号,这就是该错误的原因:

下面的代码将产生相同的错误,因为它有额外的括号(当调用 else 部分来创建向量时,你的 if 情况相同:

((vec {:a 10 :b 100}))

尝试在 REPL 中执行此操作,您将看到相同的异常:

java.lang.IllegalArgumentException: Wrong number of args (0) passed to: PersistentVector (NO_SOURCE_FILE:0)
于 2012-04-22T05:49:00.570 回答