1

我正在解决来自 4Clojure 站点的问题 22,要求我编写一个函数来计算序列中的元素。因为我曾一度搞乱了 Haskell,所以我知道 usingfold可能是这样做的方法。在阅读了它之后,我了解到我应该将其reduce用于相同的目的。这是我提交的答案:

#(reduce inc 0 %)

这背后的原因是迭代列表,并inc每次调用最初为 0 的值。但是,这不起作用。该站点抱怨“传递给:core$inc 的 args (2) 数量错误”。所以我尝试在周围添加括号inc

#(reduce (inc) 0 %)

现在它认为零参数被传递给inc. 我在这里做错了什么?

4

5 回答 5

10

所以我尝试在公司周围添加括号...

不要在 clojure 中使用括号指导编译器/解释器。在 clojure 中,每个括号都很重要,这样您只需调用一个零参数的函数。

现在,看看关于 reduce 的 clojure 文档

如果提供了 val,则返回将 f 应用于 val 和 coll 中的第一项,然后将 f 应用于该结果和第二项等的结果。

所以当你写

(reduce inc 0 [1 2 3])

实际发生的是

(inc 
   (inc 
      (inc 0 1) 2) 3)

正确的功能可能看起来像

#(reduce 
    (fn [c _] (inc c))
     0 %)
于 2013-05-23T21:30:32.140 回答
3

假设列表是

[1 2 3 4]

在你的第一个例子中,你告诉 reduce 执行这些:

(inc 0 1)
(inc 0 2)
(inc 0 3)
(inc 0 4)

显然 inc 在这里被传递了两个参数,当它需要一个时。

在您的第二次尝试中,您告诉 reduce (inc) 将返回一个函数,然后将其与值和列表一起使用。(inc) 是对带有零参数的 inc 函数的调用。

reduce 的第一个参数需要一个函数,它接受两个值并返回第一个值加一。

于 2013-05-23T21:28:43.990 回答
2

Clojurereduce可以被认为类似于 haskell 的左折叠函数foldl。计算列表中项目的haskell方法是xs这样的

foldl (const . (+1)) 0 xs

更好理解为foldl (\acc _ -> acc + 1) 0 xs

这个想法是增加折叠函数中的第一个操作数,所以我很想把它写成

(reduce #(inc (%1)) 0 xs)

但这是错误的,因为匿名函数的元数由表达式中引用的最高参数决定,而我们的折叠函数的元数必须为 2。

所以,一个聪明的解决方法: (reduce #(inc (first %&)) 0 xs)

于 2016-10-22T07:46:59.710 回答
1

我也一直在通过问题列表学习clojure。想出了这个问题的答案:

reduce + (#(for [o %] 1))
于 2017-07-22T08:48:31.587 回答
0

还有另一种方法是将序列转换为 Java 数组并调用 alength 函数:

#(alength (to-array %))
于 2014-03-29T14:24:23.450 回答