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

Известно, что монады являются теоретически подмножеством функторов и, в частности, аппликативных функторов, даже если они не указаны в системе типа Хаскелла.

Зная, что, учитывая монаду и основываясь на return и bind, как:

  • вывод fmap,
  • вывод <*>?

Ответы

Ответ 1

Ну, fmap - это просто (a -> b) -> f a -> f b, то есть мы хотим преобразовать результат монадического действия с чистой функцией. Это легко написать с обозначением:

fmap f m = do
  a <- m
  return (f a)

или, написано "raw":

fmap f m = m >>= \a -> return (f a)

Это доступно как Control.Monad.liftM.

pure :: a -> f a, конечно, return. (<*>) :: f (a -> b) -> f a -> f b немного сложнее. У нас есть действие, возвращающее функцию, и действие, возвращающее его аргумент, и мы хотим, чтобы действие возвращало его результат. В повторной нотации:

mf <*> mx = do
  f <- mf
  x <- mx
  return (f x)

Или, desugared:

mf <*> mx =
  mf >>= \f ->
  mx >>= \x ->
  return (f x)

Тада! Это доступно как Control.Monad.ap, поэтому мы можем предоставить полный экземпляр Functor и Applicative для любой монады M как следующим образом:

instance Functor M where
  fmap = liftM

instance Applicative M where
  pure = return
  (<*>) = ap

В идеале мы могли бы указать эти реализации непосредственно в Monad, чтобы облегчить определение отдельных экземпляров для каждой монады, например это предложение. Если это произойдет, не будет реального препятствия для создания Applicative суперкласса Monad, так как это гарантирует, что он не нарушит существующий код. С другой стороны, это означает, что шаблон, участвующий в определении экземпляров Functor и Applicative для данного Monad, минимален, поэтому легко быть "хорошим гражданином" (и такие экземпляры должны быть определены для любой монады).

Ответ 2

fmap = liftM и (<*>) = ap. Вот ссылки на исходный код liftM и ap. Я предполагаю, что вы знаете, как следует обозначать desugar.