In the Scalaz trait Foldable
we see the method foldMap
with the following description
Map each element of the structure to a [[scalaz.Monoid]], and combine the results.
def foldMap[A,B](fa: F[A])(f: A => B)(implicit F: Monoid[B]): B
You can use it like this:
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
My question is: What is the Clojure equivalent of Scalaz Foldable's foldmap?
I'm willing to be proven wrong, but I don't think Clojure has monoids, as such. However, check out this article that describes how you would create a monoid.
Specifically for your two examples, I would write:
(reduce + [1 2 3]) ; => 6
and
(some identity [true false true true]) ;=> true
Note that identity
is not the Identity monoid. :-)
By default Clojure has no monadic composition. For that you need libraries like algo.monads or fluokitten.
A monoid in Haskell and Skalaz is a class that implements three functions:
mempty
returns the identity elementmappend
combines two values of the same typemconcat
used to convert collections of that type to items and v.v.Clojure has no fold function that invokes all three of those; reduce
is the go-to higher order function for accumulating over a collection.
By default it takes 3 parameters: a reducer function, an accumulator and a collection. The reducer function is used to combine the accumulator and one item from the collection at a time. It need not accept identical types like mappend
. The third is always a collection, which is why mconcat
is not needed.
In the context of Clojure's 1.5 clojure.reducers
and clojure.core/reduce
, there is a monoid however: a function that returns it's identity element when called without parameters.
For instance:
(+) => 0
(*) => 1
(str) => ""
(vector) => []
(list) => ()
This 'monoid' function is used as the reducer in the two parameter version of reduce
; its 'monoidal identity' or mempty
is called to create the initial accumulator.
(reduce + [1 2 3]) => (reduce + (+) [1 2 3]) => (reduce + 0 [1 2 3])
So if you want to translate the examples here, you need to find or make a function that has such a 'monoid' implementation to use it in the dual arity reduce.
For disjunction, Clojure has 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)))))
It does have a 'monoid' implementation, ([] nil)
. However, or
is implemented as a macro to support short circuiting, and can only be used within an expression to be expanded, not as a function parameter:
(reduce or [false true false true true])
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/or, compiling
So we need a 'new' or
that's a true function for disjunction. It should also implement a no-arity version returning nil:
(defn newor
([] nil)
([f s] (if f f s)))
So now we have a function with a 'monoid' implementation, and you can use it in the dual arity reduce:
(reduce newor [true false true true])
=> true
Seems a bit complicated until you understand why Clojure implemented or
as a multiple arity macro
(or true false true true)
=> true
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With