【问题标题】:What is the Clojure equivalent of Scalaz Foldable's foldmap?Scalaz Foldable 的折叠图的 Clojure 等价物是什么?
【发布时间】:2014-02-14 11:37:29
【问题描述】:

Scalaz trait Foldable 中,我们看到method foldMap 具有以下描述

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

def foldMap[A,B](fa: F[A])(f: A => B)(implicit F: Monoid[B]): B

你可以这样使用它:

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

我的问题是:Scalaz Foldable 的折叠图对应的 Clojure 是什么?

【问题讨论】:

标签: scala clojure scalaz fold


【解决方案1】:

默认情况下,Clojure 没有单子组合。为此,您需要像 algo.monadsfluokitten 这样的库。

Haskell 和 Skalaz 中的幺半群是一个实现三个功能的类:

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

Clojure 没有调用所有这三个的折叠函数; reduce 是对集合进行累积的首选高阶函数。

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

在 Clojure 的 1.5 clojure.reducersclojure.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

【讨论】:

  • or 未实现为宏 to support variable arity ;函数也可以有多个参数。 or被实现为一个宏来支持惰性求值
【解决方案2】:

我愿意被证明是错误的,但我不认为 Clojure 有这样的幺半群。但是,请查看 this article,它描述了如何创建一个幺半群。

对于你的两个例子,我会写:

(reduce + [1 2 3]) ; => 6

(some identity [true false true true]) ;=> true

注意identity 不是 Identity monoid。 :-)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-15
    • 2014-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-01
    • 2014-06-12
    相关资源
    最近更新 更多