Recursion Clojure从递归调用返回值

Recursion Clojure从递归调用返回值,recursion,clojure,Recursion,Clojure,我正在研究Clojure算法来解决这里提出的问题:我遇到了一个小问题 我使用的是递归算法,一开始可能不是正确的选择,遍历一个按最高到最低的值权重比排序的玩偶结构向量。有关守则如下: (defn get-carryable-dolls [dolls carryable-dolls] (def doll (first dolls)) ;initializing for use in multiple places (def rest-dolls (rest dolls)) ;initi

我正在研究Clojure算法来解决这里提出的问题:我遇到了一个小问题

我使用的是递归算法,一开始可能不是正确的选择,遍历一个按最高到最低的值权重比排序的玩偶结构向量。有关守则如下:

(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))
    )
  )
)
代码工作正常;可返回的玩偶包含要作为解决方案返回的玩偶结构的所需向量。不幸的是,当我尝试将可返回的玩偶向量返回到调用位置时,我收到以下错误:

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功能更喜欢简洁的错误消息,所以我不知道如何修复它。如果有人有任何建议,我将不胜感激

提前谢谢

编辑:


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

这段代码中有太多的paren,它们导致了问题。我强烈建议您以其他人的方式格式化代码,这将使类似这样的错误很容易突出。我甚至猜不出你想做什么,所以我无法重写整个代码段,但需要注意的是if的语法是:


在这些事情上不允许有额外的参数:例如,如果真的12是可以的,但是如果真的12会尝试将真作为一个函数调用,并且失败,因为它是一个布尔值。如果要将表达式分组并计算其副作用,则需要执行expr1 expr2,而不是expr1 expr2。

If代码周围有额外的参数,这就是错误的原因:

以下代码将产生相同的错误,因为当调用else部分创建向量时,它在if中具有相同的额外参数:

((vec {:a 10 :b 100}))
尝试在REPL中执行此操作,您将看到相同的异常:

java.lang.IllegalArgumentException: Wrong number of args (0) passed to: PersistentVector (NO_SOURCE_FILE:0)

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

去掉多余的和错误的括号 以更惯用的方式格式化代码 对本地名称绑定使用loop/let而不是def 使用seq检查空列表 在添加元素之前,删除对空可携带玩偶序列的不必要检查 如果没有辅助功能(例如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))

谢谢你的建议。我将研究减少括号,看看这是否能提供任何提示。这就是在首次使用该语言后24小时内试图解决类似这样的代码问题的危险。因此,如果这已经计算出正确的值,但由于意外地将某个对象作为函数调用而失败,那么您可能可以通过用do a b替换a b的每个实例来修复它。一旦你更加熟悉clojure,你可以返回并删除这个函数中的所有def,这是一个非常命令式风格的保留。我不确定它是否失败,因为它意外地将某个东西作为函数调用。这很可能是因为我在语言交流方面缺乏经验,但老实说,在粘贴的语句中,我看不到一个括号可以删除的例子。你能提供一个更具体的例子吗?例如,从第3行开始的一对括号是多余的。函数体周围没有像大括号一样的括号。@neveu:谢谢你的例子;我已经删除了多余的括号,但不幸的是,它没有解决问题。你在代码中到处撒括号,就像它们是花括号一样。你能提供一个具体的例子,说明我可以删除括号,但仍然得到相同的结果吗?我在这方面非常,非常新。例如:在第一个条件之后,如果有两个圆括号;第一个是不必要的,第二个是正确的,因为它是第二个if的左括号。@Óscar López谢谢,我已经用我所做的更改和一些显示流控制的注释更新了代码,希望能说明我的思维过程。你的if语句周围还有额外的参数。你也不需要第一个,因为一个空序列仍然是一个序列,所以你不需要特别对待它;只需使用conj carryable娃娃即可。如果你真的需要局部变量-和
您不需要它们中的大多数-使用let not def,因为def定义了一个全局变量。skuro,谢谢您的帮助。您的第二个解决方案提供了我正在寻找的解决方案,显然比我最初发布的解决方案简洁得多。你是个救生员!
(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))