Чем монада-трансформер отличается от монады? - PullRequest
22 голосов
/ 21 февраля 2011

Вопрос говорит сам за себя, правда. Я знаю, что (Scala) Monad выглядит так:

trait Monad[M[_]] {
  def pure[A](a : A) : M[A]
  def bind[A, B](ma : M[A], f : A => M[B]) : M[B]
}

Как выглядит Монада Трансформер ? И для чего они используются?

<ч /> EDIT . Рассмотрим следующий сеанс REPL: если преобразователь монад каким-то образом украшает монаду с возможностями считывателя (или наоборот)

Допустим, я просто хочу использовать replicateM из Scalaz ;

scala> import scalaz._; import Scalaz._
import scalaz._
import Scalaz._

scala> some(4).replicateM[List](2)
res20: Option[List[Int]] = Some(List(4, 4))

Теперь, скажем, вместо Option[Int] мне нужно прочитать значение Int из File:

scala> val f = (_ : java.io.File) => some(1)
f: (java.io.File) => Option[Int] = <function1>

Итак, я могу относиться к этому читателю , как к монаде?

scala> ReaderT(f).replicateM[List](2)
<console>:16: error: value replicateM is not a member of scalaz.ReaderT[Option,java.io.File,Int]
       ReaderT(f).replicateM[List](2)
                  ^

Ошибка, нет.

Извиняюсь, если все это кажется глупым, я просто пытаюсь понять, какую прекрасную доброту моя упаковка File => Option[Int] в ReaderT может действительно купить мне.

Ответы [ 3 ]

8 голосов
/ 21 февраля 2011

Трансформаторы монад используются для объединения / расширения монад (добавьте возможности одной монады к другой). Например, ReaderT (Reader Transformer) обогащает данную монаду M возможностями Reader (преобразует данную монаду в Reader, сохраняя оригинальные свойства M).

В то же время, Monad Transformers - это обычные монады, которые имеют bind, return и другие операции.

Примеры монадных трансформаторов можно найти в Scalaz - например, для Считыватель и Состояние монад .

7 голосов
/ 24 апреля 2011

Преобразователи монад - это функции типов, которые при применении к типу монад генерируют новую монаду, которая сочетает в себе поведение обоих компонентов.

например. в диспетчере окон xmonad вычисления выполняются внутри:

newtype X a = X (ReaderT XConf (StateT XState IO) a)

, то есть Reader, состоящий из State и IO монады.

  • Reader предоставляет доступ к постоянной памяти
  • State предоставляет форму состояния чтения-записи
  • IO допускает произвольные внешние эффекты

Обратите внимание, что монадные преобразования являются, таким образом, типами более высокого ранга. Они берут монадический тип вида (* -> *) и выдают новый тип такого типа.

Как всегда, на вики Haskell есть полезный контент:

С чего все началось:

1 голос
/ 23 февраля 2011

Я не думаю, что Reader предназначен для чтения значений из файла. Уверен, это для чтения значений конфигурации. Я думаю об этом как об альтернативе глобальным переменным, статическим переменным или динамическим / локальным переменным потока (называемым «специальными переменными» в Common Lisp или иногда переменными переменными в Scheme с его «жидким разрешением»). Поэтому используйте Reader / ReaderT вместо доступа к глобальной или динамической переменной и не передавайте параметры в каждый из ваших методов, которым может потребоваться доступ к некоторой опции конфигурации. Это может быть полезно, когда какой-то очень глубокий фрагмент кода внезапно требует доступа к новой опции конфигурации. Вы можете передать эту опцию из функции main (), незаметно получить доступ к глобальной или использовать Reader / ReaderT.

...