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 element
mappend
combines two values of the same type
mconcat
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