Составьте карту и уменьшите монаду для Clojure ... А как насчет Juxt Monad? - PullRequest
6 голосов
/ 27 марта 2012

Изучая Clojure, я целую вечность пытался понять монады - что это такое и как мы можем их использовать ... с не слишком большим успехом.Тем не менее, я нашел отличную серию «Монады для чайников» - http://vimeo.com/20717301 - Брайана Марика для Clojure

До сих пор мое понимание монад таково, что это своего рода макрос в этомон позволяет написать набор утверждений в форме, которая легко читается, но монады гораздо более формализованы.Мои наблюдения ограничиваются двумя примерами:

1.Монада идентификации (или монада let) взята из http://onclojure.com/2009/03/05/a-monad-tutorial-for-clojure-programmers-part-1/

Форма, которую мы хотим записать:

(let [a  1
      b  (inc a)]
  (* a b))

и соответствующая монада

(domonad identity-m
    [a  1
     b  (inc a)]
 (* a b))

2.Монада последовательности (или монада for) взята из http://onclojure.com/2009/03/06/a-monad-tutorial-for-clojure-programmers-part-2/

Форма, которую мы хотим написать:

(for [a (range 5)
      b (range a)]
  (* a b))

и соответствующая монада

(domonad sequence-m
  [a (range 5)
   b (range a)]
  (* a b))

Определения монад в Clojure

Просмотр источника с использованием библиотеки монад clojure - https://github.com/clojure/algo.monads:

user=>(use 'clojure.algo.monads)
nil

Монада идентификации:

user=> (source identity-m)
(defmonad identity-m
  [m-result identity
   m-bind   (fn m-result-id [mv f]
              (f mv))
  ])

последовательность монада:

user=> (source sequence-m)
(defmonad sequence-m
   [m-result (fn m-result-sequence [v]
               (list v))
    m-bind   (fn m-bind-sequence [mv f]
               (flatten* (map f mv)))
    m-zero   (list)
    m-plus   (fn m-plus-sequence [& mvs]
               (flatten* mvs))
    ])

Итак, мой вывод заключается в том, что монада является своего рода обобщенной функцией высшего порядка, которая принимает входную функцию и входные значения, добавляет свои собственныеуправляет логикой и выдает «вещь», которую можно использовать в блоке «домонад».

Вопрос 1

Итак, наконец, к вопросам: я хочунаучитесь писать монаду и скажите, что я хочу написать «монаду карты», которая имитирует форму «карты» в clojure:

(domonad map-m
  [a [1 2 3 4 5]
   b [5 6 7 8 9]]
  (+ a b))

должен быть эквивалентен

(map + [1 2 3 4 5] [5 6 7 8 9])

ивернуть значения

[6 8 10 12 14]

Если я посмотрю на источник, он должен дать мне что-то похожее на identity-m и sequence-m:

user=> (source map-m)
(defmonad map-m
   [m-result ...
    m-bind   ...
    m-zero   ...
    m-plus   ...
    ])

Вопрос 2

Я также хочу иметь возможность определить «redu-m» так, чтобы я мог написать:

(domonad reduce-m
  [a [1 2 3 4 5]]
  (* a))

это может потенциальнодай мне 1 x 2 x 3 x 4 x 5 = 120 или

(domonad reduce-m
  [a [1 2 3 4 5]
   b [1 2 3 4 5]]
  (+ a b))

даст мне (1 + 2 + 3 + 4 + 5) + (1 + 2 + 3 + 4 + 5) =30

Наконец Могу ли я также написать «монаду juxt», которая имитирует функцию juxt, но вместо передачи значений для привязки я передаю набор функций.:

(domonad juxt-m
  [a #(+ % 1)
   b #(* % 2)]
  '([1 2 3 4 5] b a) )

дает

[ [2 2] [4 3] [6 4] [8 5] [9 6] ] 

Потенциально, я мог бы делать все эти вещи с помощью макросов, поэтому я не знаю, насколько полезными будут эти «монады» или онидаже рассматривал «монады» ... Имея все ресурсы в интернете, мне кажется, что если я хочу изучать монады должным образом, я должен выучить Хаскель, и сейчас изучать другую синтаксическую форму слишком сложно.Я думаю, что нашел некоторые ссылки, которые могут быть актуальны, но это слишком загадочно для меня

Пожалуйста, может кто-нибудь пролить свет!

Ответы [ 3 ]

9 голосов
/ 29 марта 2012

Ваши примеры не монады. Монада представляет собой составные вычислительные шаги. В монаде тривиальной идентичности вычислительный шаг - это просто оценка выражения. В возможно монаде шаг - это выражение, которое может быть успешным или неудачным. В монаде последовательности шаг - это выражение, которое выдает переменное число результатов (элементов последовательности). В монаде писателя вычислительный шаг представляет собой комбинацию вычисления выражения и вывода журнала. В монаде состояния вычислительный этап включает в себя доступ и / или изменение фрагмента изменяемого состояния.

Во всех этих случаях монадная сантехника заботится о правильном совмещении шагов. Функция m-result упаковывает «простое» значение для встраивания в схему монадических вычислений, а функция m-bind передает результат одного вычислительного шага на следующий вычислительный шаг.

В (map + a b) нет вычислительных шагов для объединения. Там нет понятия порядка. Это просто оценка вложенного выражения. То же самое для уменьшения.

2 голосов
/ 28 марта 2012

Я нашел несколько действительно хороших ресурсов для монад:

Так из руководства Джима- http://www.clojure.net/2012/02/06/Legalities/ - он дает три аксиомы для определения функций «bind-m» и «redu-m»:

Идентичность Первый закон монады может бытьзаписывается как

(m-bind (m-результат x) f) равно (fx)

Что это означает, что любой m-результат влияет на xчтобы превратить его в монадическое значение, m-bind отменяет действие перед применением f к x.Итак, что касается m-bind, m-result является своего рода функцией идентичности.Или в терминологии теории категорий, ее единица.Вот почему иногда вы увидите его с именем «unit».

Обратная идентичность Второй Закон Монады можно записать как

(m-bind mvm-result) равно mv, где mv - монадическое значение.

Этот закон является чем-то вроде дополнения к первому закону.Это в основном гарантирует, что m-результат является монадической функцией и что независимо от того, что m-bind делает с монадическим значением для извлечения значения, m-результат отменяет создание монадического значения.

Ассоциативность Третий закон монады можно записать как

(m-bind (m-bind mv f) g) равно (m-bind mv (fn [x] (m-bind (fx))g))) где f и g - монадические функции, а mv - монадическое значение.

Этот закон говорит о том, что не имеет значения, применяется ли f к mv, а затем к g применяетсярезультат, или была ли создана новая монадическая функция из композиции f и g, которая затем применяется к mv.В любом порядке результирующее значение является одним и тем же монадическим значением.Другими словами, m-bind ассоциативно связан с левой и правой частями.

В http://www.clojure.net/2012/02/04/Sets-not-lists/ он дает монаду, которая принимает наборы в качестве входных данных вместо списков.Проработаем все примеры ...

2 голосов
/ 27 марта 2012

Ваши вопросы не относятся к типу монад.Похоже, они больше похожи на синтаксический сахар, и вы можете сделать это с помощью макросов, и я даже не буду предлагать вам это делать, потому что map, сокращение и т. Д. Являются простыми функциями, и нет необходимости делать их интерфейс сложным.

Причина в том, что эти случаи не являются монадами, потому что моанды являются своего рода усиленными значениями, которые заключают в себе нормальные значения.В случае карты и сокращения вектор, который вы используете, не нуждается в усилении, чтобы позволить ему работать в карте или уменьшении.

Было бы полезно попробовать macroexpand для выражений domoand.Например: пример монады последовательности должен расшириться до чего-то вроде:

(bind (result (range 5)) 
   (fn [a] 
      (bind (result (range a))
        (fn [b] (* a b))
   )))

Где связывание и результат - это функции, определенные в монаде последовательности m-bind и m-result.Таким образом, в основном векторное выражение (я) после запроса становится вложенным, а выражение (я) после вектора используются, как и в предыдущем случае (* ab) вызывается как есть (только при условии, что предоставляются значения a и b)монадой).В вашем примере с монадой map векторные выражения должны быть такими, как есть, и последнее выражение (+ ab) должно как-то означать (map + ab), а это не то, что должна делать монада.

...