这是如何与减少函数在Clojure评估代码?



以下是Clojure代码:

(reduce (fn [r x] (if (nil? x) r (conj r x)))  
[]  
[:mouse nil :duck nil :lory nil])

在REPL中,它的求值为[:mouse :duck :lory]

我的问题是,代码是如何评估的?

根据我的理解,r[],x[:mouse nil :duck nil :lory nil]nil? x为假,因此计算结果为(conj r x)。但是x是一个向量,而不是一个元素,那么它如何将一个元素添加到conj中的空向量r中呢?我不知道,但我的方法有些地方错了。输出是不带nil值的动物名称向量。谁能给我解释一下代码的执行。谢谢。

你的问题似乎是理解reduce是如何工作的。我想让您参考源代码,但它只是映射到Java实现,所以我不得不伪造它。

您正在执行的reduce类型-提供初始值-可能已编码如下:

(defn reduce [f init coll]
(loop [acc init, tail coll]
(if (seq tail)
(recur (f acc (first tail)) (rest tail))
acc)))

可以看到,它通过序列coll工作,将函数f应用于acc和序列中的第一个值,以生成新的acc。当没有更多的序列时,它返回acc

这如何适用于你的例子?

(fn [r x] (if (nil? x) r (conj r x)))

…忽略nil,xs,但conjs在累积向量r的末尾。您的代码或多或少相当于…

(remove nil? [:mouse nil :duck nil :lory nil])
=> (:mouse :duck :lory)

…除了你得到的是一个惰性序列而不是一个向量。

由FredOverflow的Clojure Transducers提供,您可以将减少fn包装在这个logging函数中,以在每个步骤中打印不同的参数(r和x):

(defn logging [f]
(fn [& args]
(prn args)
(apply f args)))
(reduce (logging (fn [r x] (if (nil? x) r (conj r x))))
[]  
[:mouse nil :duck nil :lory nil])

用户=比;([]:鼠标)
             ([: 鼠标]nil)
             ([: 老鼠:鸭)
             ([: 鼠:鸭]nil)
             ([: 老鼠:鸭]:洛里)
             ([: 老鼠:鸭:洛里]nil)

所以只添加关键字(不是nil),从[]开始。最后返回[:mouse :duck :lory]

相关内容

  • 没有找到相关文章

最新更新