我陷入了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只是输入一个新行并闪烁。
编辑:修复了复发。
答案 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
表单从未被执行。以下是执行流程:
loop
表单; i
设置为 0。if
表单。then
的 if
分支的代码,返回 1。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”。