Почему монады монахов государства и читателя, в то время как монада-писатель является кортежем?

Я новичок в Haskell, и я думаю, что понимаю монады и их механики (по крайней мере, для списка, штата, может быть, писателей и читателей), но я хочу понять, почему они были определены так, как они, или почему они должны быть такими, какие они есть, чтобы помочь моей интуиции в размышлении о них.

В частности, что такое чтение, которое делает монады-читатели или государственные монады необходимыми функциями (т.е. \s -> (a,s)), а не только такими данными, как монада-писатель (т.е. (w,a))?

Кроме того, может ли монада писателя использоваться в качестве государственной монады, где журнал используется как строковое представление состояния, если функциональность MonadPlus не используется? Является ли монадическая функция, используемая с монадами-писателями, разрешенной для просмотра текущего журнала и изменения, если это необходимо, или это только функция связывания монады-писателя, которая разрешена для просмотра журнала?

Кроме того, почему монады определены в терминах монадических функций, которые с типом a -> m b, а не с типом m a -> mb? Что так естественно в отношении функции, идущей от базового типа к монадированному типу?

Спасибо за ваши ответы.

Ответ 1

Государство и монада-читатели зависят от ценности того, что нас интересует. Нам нужно иметь доступ к нему, иначе как мы могли бы написать что-то вроде

foo = do
 i <- get
 return $ if i == 1 then 2 else 3

Итак, наша государственная монада, естественно, выглядит как нечто, что принимает состояние, делает вещи и создает новый.

Аналогично с монадой-читателем мы берем какое-то состояние, магию и производим вывод (но не новое состояние, так как оно Reader s a <=> s -> a.

Теперь это сильно отличается от монады-писателя. В писателе нас не волнует то, что было застряло в государстве ранее, все, что мы хотим сделать, это взять наше нынешнее состояние и зажечь еще кое-что. Поскольку наше состояние является моноидом, у нас есть гарантированное начальное состояние mempty и способ застревания в mappend. Это означает, что мы можем "запускать" каждое вычисление в пустом контексте, так сказать, и просто сливать выходы вместе и получать одинаковые результаты.

Хорошо, теперь есть несколько вопросов, поэтому я поеду один за раз

  • Если монада-писатель имела доступ к ранее написанным результатам, тогда она будет выглядеть как s -> (s, a), которая является государственной монадой:) Итак, что бы вы ни делали с государственной монадой, это можно сделать с помощью этой расширенный писатель.

    На самом деле обе монады StateT и WriterT имеют экземпляры MonadPlus, поэтому я не уверен, что вы здесь делаете.

  • Так как не существует произвольной функции m a -> a, нам нужно каким-то образом развернуть вычисление для просмотра результатов ala >>=, а так как return :: a -> m a делает тривиальным идти другим путем, это более общий переход от простого к монадическому значению. В противном случае у нас просто были бы эти бесполезные IO String, STM Int и то, что мы не могли зависеть от остальных наших вычислений, так как fmap не позволит нам поднимать больше побочных эффектов.

Ответ 2

Они определяются по-разному, потому что они делают разные вещи.

Возьмите монаду читателя. Начните с размышлений о том, что это значит, а не о том, как это работает.

Вычисление в монаде читателя - это то, которое зависит от дополнительной информации, читающей "среды". Таким образом, Reader Env Int является Int, который зависит от среды (типа Env; если я оцениваю ее с помощью одной среды, я получаю одно значение Int, и если я оцениваю ее с другой средой, Я получаю другое значение Int. Если у меня нет среды, я не могу знать, какое значение имеет значение Reader Env Int.

Теперь, какое значение даст мне Int, если я дам ему Env? Функция типа Env -> Int! Таким образом, обобщение на e -> a является монадой для каждого ea является параметром типа монады; (->) e, если вам нравится префиксная нотация).

Теперь подумайте о значении монады-писателя. Вычисление в монаде писателя дает значение, но оно также дает дополнительное значение "сбоку": значение "log". И когда мы свяжем последовательность монадических вычислений из монады-писателя, значения журнала будут объединены (если мы хотим, чтобы тип журнала был моноидом, тогда это гарантирует, что значения журнала могут быть объединены без каких-либо других знаний о том, что они представляют). Таким образом, Writer Log Int является Int, который также имеет значение типа Log.

Это очень похоже на пару: (Log, Int). И это обобщает на (w, a) как монаду для каждого wa, являющимся параметром типа монады). Ограничение моноида на w, которое гарантирует совмещение значений журнала, также означает, что мы имеем очевидное начальное значение (элемент идентичности для monoid: mempty), поэтому нам не нужно ничего предоставлять, чтобы получить значение из значения в монаде писателя.

Модификация государственной монады s -> (a, s) на самом деле в значительной степени является комбинацией вышеизложенного; a State S Int является Int, который зависит от значения S (поскольку читатель зависит от среды), а также создает значение S, где связывание последовательности вычислений состояний должно приводить к каждому из них "видя" состояние, произведенное предыдущим. Значение, зависящее от значения состояния, является функцией значения состояния; если на выходе появляется "вместе с" новым значением состояния, нам нужна пара.

Ответ 3

Кроме того, почему монады определены в терминах монадических функций, которые с типом a -> m b, а не с типом m a -> m b? Что так естественно в отношении функции, идущей от базового типа к монадированному типу?

(Я взял освобождение от добавления пробела между m и b в mb).

Видите, это делает его монадой. Без этого у нас уже есть функции a -> b и ссылка из них на f a -> f b (эта ссылка называется "функтором" и подчиняется законам для fmap). Но функтор только дает вам проекцию одного "мира" (категории) в другую - так что, какие бы законы ни находились в первом мире, они также сохраняются во втором мире (например, если a + b == c, то f a (f +) f b == f c). Монада дает вам мост между "мирами".

Кроме того, вам не нужно определять монаду с точки зрения поведения с функциями типа a -> m b, но одна минимальная спецификация монады говорит вам, как >>=, return, id и (.) относиться. Можно определить монаду, используя >=>, return, id и (.), или используя join, return, id и (.) - вы видите, это действительно не так вопрос, который функция выбрать. Оказывается, >>= удобно для цепочки.

Ответ 4

В частности, что такое чтение, которое делает монады-читатели или государственные монады необходимыми функциями (т.е. \s -> (a,s)), а не только такими данными, как монада-писатель (т.е. (w,a))?

Функции - это просто данные. Это просто те типы, которые лучше всего соответствуют желаемой семантике.

Кроме того, может ли монада-писатель использоваться в качестве государственной монады, где журнал используется как строковое представление состояния, если функция MonadPlus не используется?

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

Является ли монадическая функция, используемая с монадами-писателями, разрешенной для просмотра текущего журнала и изменения, если это необходимо, или это только функция связывания монады-писателя, которая разрешена для просмотра журнала?

Вы заметите, что монада Writer имеет функцию tell, которая фактически добавляет новые данные в журнал.

Кроме того, почему монады определены в терминах монадических функций, которые с типом a -> m b, а не с типом m a -> m b? Что так естественно в отношении функции, идущей от базового типа к монадированному типу?

Думаю, лучший ответ - "потому что a -> m b оказывается более полезным".