陷入Clojure循环,需要一些指导

时间:2010-07-11 08:50:46

标签: loops if-statement clojure lisp

我陷入了Clojure循环,需要帮助才能离开。

我首先要定义一个向量

(def lawl [1 2 3 4 5])

我做

(get lawl 0)

获得“1”作为回报。现在,我想要一个循环来获取向量中的每个数字,所以我这样做:

(loop [i 0]
   (if (< i (count lawl)) 
     (get lawl i) 
       (recur (inc i))))

在我的脑海中,这应该将i的值设置为nil,然后如果我低于lawl向量的计数,它应该得到每个lawl值然后用i增加i变量并再试一次,得到向量中的下一个值。

然而,这不起作用,我花了一些时间试图让它工作并完全卡住,会感激一些帮助。我也尝试将“if”改为“when”,结果相同,它不提供任何数据,REPL只是输入一个新行并闪烁。

编辑:修复了复发。

3 个答案:

答案 0 :(得分:7)

你需要考虑什么是“获得每个lawl值”的意思。你的get调用确实“获得”了适当的值,但由于你从不对它做任何事情,所以它被简单地丢弃了; Bozhidar建议添加println是一个很好的建议,可以让你看到循环确实访问lawl的所有元素(只需用(get ...)替换(println (get ...)),修复Bozhidar提到的(inc) =&gt; (inc i)之后的事情。)

也就是说,如果您只想依次对每个号码执行某些操作,loop / recur根本不是一个很好的方法。以下是其他一些内容:

;;; do some side-effecty thing to each number in turn:
(dotimes [i (count lawl)]
  (println (str i ": " (lawl i)))) ; you don't really need the get either

;; doseq is more general than dotimes, but doesn't give you equally immediate
;; acess to the index
(doseq [n lawl]
  (println n))

;;; transform the lawl vector somehow and return the result:
; produce a seq of the elements of lawl transformed by some function
(map inc lawl)
; or if you want the result to be a vector too...
(vec (map inc lawl))
; produce a seq of the even members of lawl multiplied by 3
(for [n lawl
      :when (even? n)]
  (* n 3))

这只是一个开始。有关Clojure标准图书馆的精彩游览,请参阅Mark Volkmann撰写的Clojure -- Functional Programming for the JVM文章。

答案 1 :(得分:3)

(recur (inc))应为(recur (inc i))

即便如此,如果你想要一个可以添加打印表达式的数字列表,这个代码最后会返回1 :-)在这样的场景中根本不需要基于Btw索引的循环。

(loop [list [1 2 3 4 5] ]
         (if (empty? list)
             (println "done")
             (do
              (println (first list))
              (recur (rest list)))))

答案 2 :(得分:1)

好吧,我在这方面已经晚了大约 10-1/2 年,但这里是:

这里的问题是对如何使用 if 函数的参数的一个非常普遍的误解。 if 接受三个参数 - condition/predicate,谓词为真时要执行的代码,以及谓词为假时要执行的代码。在这种情况下,提供了 true 和 false 两种情况。也许如果我们修复缩进并添加一些适当的注释,我们将能够更容易地看到发生了什么:

(loop [i 0]
  (if (< i (count lawl)) 
    (get lawl i)       ; then 
    (recur (inc i))))  ; else

所以问题不在于代码在循环中“卡住”——问题在于 recur 表单从未被执行。以下是执行流程:

  1. 输入loop表单; i 设置为 0。
  2. 输入了 if 表单。
  3. 执行谓词形式并发现它为真。
  4. 执行 thenif 分支的代码,返回 1。
  5. 然后执行会落在 loop 表单的底部。

现在我听到人们尖叫“等等!什么?!?”。是的 - 在 if 表单中,“then”和“else”分支中只能有一个表单。 “可是……这太蠢了!”我听你说。嗯...不是真的。您只需要知道如何使用它。有一种方法可以将 Clojure 中的多个表单组合到一个表单中,这可以通过使用 do 来完成。如果我们想将 (get lawl i)(recur... 组合在一起,我们可以将其写为

(loop [i 0]
  (if (< i (count lawl)) 
    (do
      (get lawl i)       ; then 
      (recur (inc i))
    )
  )
)

如您所见,我们在此 if 表单上没有“else”分支 - 相反,(get...(recur... 表单由 (do 组合在一起,所以他们一个接一个执行。因此,在通过 lawl 向量重复出现后,上面的代码片段返回 nil,这有点难看。所以让我们让它返回更多信息:

(loop [i 0]
  (if (< i (count lawl)) 
    (do
      (get lawl i)         ; then
      (recur (inc i)))
    (str "All done i=" i)  ; else
  )
)

现在我们的 else 分支返回“All done i=5”。