2014-02-14 4 views
6

В Scalaz trait Foldable мы видим method foldMap со следующим описаниемЧто такое эквивалент Clojure раскладушки Scalaz Foldable?

Карта каждого элемента структуры к [[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: [email protected]@[Boolean,scalaz.Tags.Disjunction] = true 

Мой вопрос: Что такое Clojure эквивалент foldmap Scalaz Складная в?

+0

Связанных: [Как написать моноидный протокол в Clojure?] (http://stackoverflow.com/q/10767793/406435) – senia

ответ

8

По умолчанию 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 
+3

'или' не реализован как макрос 'для поддержки переменной arity'; функции могут иметь многообразие. 'или' реализовано как макрос для поддержки * ленивой оценки *. – omiel

2

Я готов быть доказанным неправильно, но я не думаю, что у Clojure есть моноиды, как таковые. Однако посмотрите this article, в котором описывается, как создать моноид.

Специально для двух примеров, я хотел бы написать:

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

и

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

Обратите внимание, что identity является не тождественность моноидом. :-)

Смежные вопросы