默认情况下,Clojure 没有单子组合。为此,您需要像 algo.monads 或 fluokitten 这样的库。
Haskell 和 Skalaz 中的幺半群是一个实现三个功能的类:
-
mempty 返回标识元素
-
mappend 结合了两个相同类型的值
-
mconcat 用于将该类型的集合转换为项目和 v.v.
Clojure 没有调用所有这三个的折叠函数; reduce 是对集合进行累积的首选高阶函数。
默认情况下,它需要 3 个参数:一个 reducer 函数、一个累加器和一个集合。 reducer 函数用于一次组合累加器和集合中的一项。它不需要接受像mappend 这样的相同类型。第三个总是一个集合,这就是为什么不需要mconcat。
在 Clojure 的 1.5 clojure.reducers 和 clojure.core/reduce 的上下文中,有一个幺半群:一个在不带参数调用时返回其标识元素的函数。
例如:
(+) => 0
(*) => 1
(str) => ""
(vector) => []
(list) => ()
这个'monoid'函数在reduce的双参数版本中用作reducer;它的“monoidal identity”或mempty被调用来创建初始累加器。
(reduce + [1 2 3]) => (reduce + (+) [1 2 3]) => (reduce + 0 [1 2 3])
因此,如果您想翻译这里的示例,您需要找到或制作一个具有这种“monoid”实现的函数,以便在对偶数量化简中使用它。
对于析取,Clojure 有 or:
(defmacro or
"Evaluates exprs one at a time, from left to right. If a form
returns a logical true value, or returns that value and doesn't
evaluate any of the other expressions, otherwise it returns the
value of the last expression. (or) returns nil."
{:added "1.0"}
([] nil)
([x] x)
([x & next]
`(let [or# ~x]
(if or# or# (or ~@next)))))
它确实有一个“monoid”实现,([] nil)。但是or被实现为宏来支持短路,并且只能在要扩展的表达式中使用,不能作为函数参数:
(reduce or [false true false true true])
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/or, compiling
所以我们需要一个“新的”or,这是一个真正的析取函数。它还应该实现一个返回 nil 的无参数版本:
(defn newor
([] nil)
([f s] (if f f s)))
所以现在我们有了一个带有“monoid”实现的函数,您可以在对偶数减少中使用它:
(reduce newor [true false true true])
=> true
在您了解 Clojure 为何将 or 实现为多元宏之前,这似乎有点复杂
(or true false true true)
=> true