Использование суперкласса монады в объявлении экземпляра монады?

Я реализую очень простую структуру параллелизма бедного человека со следующим типом данных:

data C m a = Atomic (m (C m a)) | Done a

Я создаю экземпляр монады для этого:

instance Monad m => Monad (C m) where
  (>>=) (Atomic m) f      = Atomic $ (liftM (>>= f) m)
  (>>=) (Done v) f        = f v
  return                  = Done

Q1. Правильно ли я говорю Atomic $ (liftM (>>= f) m) создает новый Atomic монада, которая содержит результат f (* -> *) применяется к значению внутри m?

Q2. Правильно ли я сказал, что суперкласс Monad m используется здесь, чтобы включить использование liftM? Если это так, то как это пример Monad класс, почему нет доступа liftM напрямую?

1 ответ

Решение

Q1. Это создает Atomic значение Монада - это отображение на уровне типа. поскольку f это второй аргумент >>= из C m a мы знаем его тип

f :: Monad m => a -> C m b

следовательно

(>>= f) :: Monad m => C m a -> C m b

является f расширен, чтобы развернуть свой аргумент, и

liftM (>>= f) :: (Monad m1, Monad m) => m1 (C m a) -> m1 (C m b)

просто поднимает превращение в m1 который в ваших настройках объединен с m, Когда вы извлекаете значение m от Atomic и передать его liftM вы используете монаду m связать (через liftM) извлечь внутреннюю C m a быть переданным f, Вторая часть liftM определение переупаковывает результат как m (C m b) в которую вы завернули Atomic, Так да.

Q2. Да. Но это liftM основной монады m, liftM за C m a определяется с точки зрения экземпляра (его >>= а также return). Используя C m a "s liftM (если вам удалось определить >>= с точки зрения liftM) вы получите циклическое определение. Вам нужно ограничение Monad m создать сантехнику для m (C m a) путешествовать по >>= а также f, На самом деле, как указал Бенджамин Ходжсон, Monad m является излишне сильным контентом, Functor m было бы достаточно. Дело в том, что C на самом деле Free вместе с соответствующими реализациями дают наибольшее понимание в этом вопросе.

Другие вопросы по тегам