По умолчанию Clojure не имеет монадической композиции. Для этого вам нужны библиотеки, такие как algo.monads или fluokitten.
Моноид в Haskell и Skalaz это класс, который реализует три функции:
mempty
возвращает элемент идентичности
mappend
сочетает в себе два значения одного и того же типа
mconcat
используется для преобразования коллекции, которые тип к элементам и vv
Clojure не имеет функции fold, которая вызывает все три из них; reduce
- функция возврата к более высокому порядку для накопления над коллекцией.
По умолчанию он принимает 3 параметра: функцию редуктора, аккумулятор и коллекцию. Функция редуктора используется для одновременного объединения аккумулятора и одного элемента из коллекции. Не нужно принимать идентичные типы, такие как mappend
. Третий - это всегда коллекция, поэтому mconcat
не требуется.
В контексте Clojure лет 1,5 clojure.reducers
и clojure.core/reduce
, там это моноид однако: это функция, которая возвращает это единичный элемент при вызове без параметров.
Например:
(+) => 0
(*) => 1
(str) => ""
(vector) => []
(list) =>()
Эта функция «моноид» используется в качестве восстановителя в версии на два параметра reduce
; его «моноидальная идентичность» или mempty
вызывается для создания исходного аккумулятора.
(reduce + [1 2 3]) => (reduce + (+) [1 2 3]) => (reduce + 0 [1 2 3])
Так что, если вы хотите перевести примеры здесь, вам нужно найти или сделать функцию, которая имеет такую реализацию «моноидную», чтобы использовать его в двойной арности уменьшить.
Для дизъюнкции, 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 [email protected])))))
Это есть реализация 'моноидное', ([] 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
это истинная функция для дизъюнкции. Он также должен осуществлять не-Арности версии возвращающегося ноль:
(defn newor
([] nil)
([f s] (if f f s)))
Так что теперь у нас есть функция с реализацией «моноидной», и вы можете использовать его в двойной арности уменьшить:
(reduce newor [true false true true])
=> true
Кажется немного сложнее, пока вы не поймете, почему Clojure реализована or
как множественная арность макро
(or true false true true)
=> true
Связанных: [Как написать моноидный протокол в Clojure?] (http://stackoverflow.com/q/10767793/406435) – senia