什么是Clojure相当于Scalaz Foldable的折叠图?

haw*_*eye 6 scala clojure fold scalaz

Scalaz特征中,Foldable我们看到了具有以下描述的方法foldMap

将结构的每个元素映射到[[scalaz.Monoid]],并合并结果.

def foldMap[A,B](fa: F[A])(f: A => B)(implicit F: Monoid[B]): B
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

scala> List(1, 2, 3) foldMap {identity}
res1: Int = 6

scala> List(true, false, true, true) foldMap {Tags.Disjunction}
res2: scalaz.@@[Boolean,scalaz.Tags.Disjunction] = true
Run Code Online (Sandbox Code Playgroud)

我的问题是:Clojure相当于Scalaz Foldable的折图?

Nie*_*lsK 8

默认情况下,Clojure没有monadic组合.为此你需要像algo.monadsfluokitten这样的库.

Haskell和Skalaz中的monoid是一个实现三个函数的类:

  • mempty 返回标识元素
  • mappend 结合了两个相同类型的值
  • mconcat 用于将该类型的集合转换为items和vv

Clojure没有折叠函数可以调用所有这三个函数; reduce是用于累积集合的高阶函数.

默认情况下,它需要3个参数:reducer函数,累加器和集合.reducer函数用于一次合并累加器和集合中的一个项目.它不需要接受相同的类型mappend.第三个总是一个集合,这就是为什么mconcat不需要.

在Clojure的1.5的范围内clojure.reducers,并clojure.core/reduce不过一个幺:返回它的标识元素时不带参数调用的函数.

例如:

(+) => 0 
(*) => 1
(str) => ""
(vector) => []
(list) => ()
Run Code Online (Sandbox Code Playgroud)

这个'monoid'函数在两个参数版本中用作reducer reduce; 它的'monoidal identity'或被mempty调用来创建初始累加器.

(reduce + [1 2 3]) => (reduce + (+) [1 2 3]) => (reduce + 0 [1 2 3])

因此,如果你想在这里翻译这些例子,你需要找到或创建一个具有这种'monoid'实现的函数,以便在双arity reduce中使用它.

对于脱节,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)))))
Run Code Online (Sandbox Code Playgroud)

它确实有'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
Run Code Online (Sandbox Code Playgroud)

所以我们需要一个"新" or,这是一个真正的分离功能.它还应该实现一个返回nil的无冗余版本:

(defn newor
  ([] nil)
  ([f s] (if f f s)))
Run Code Online (Sandbox Code Playgroud)

所以现在我们有一个带有'monoid'实现的函数,你可以在双arity reduce中使用它:

(reduce newor [true false true true])
=> true
Run Code Online (Sandbox Code Playgroud)

看起来有点复杂,直到你理解为什么Clojure实现or为多个arity宏

(or true false true true)
=> true
Run Code Online (Sandbox Code Playgroud)

  • `或`没有实现为宏`以支持变量arity`; 函数也可以有多个arity.`或`实现为支持*懒惰评估*的宏. (3认同)