Использование суперкласса монады в объявлении экземпляра монады?
Я реализую очень простую структуру параллелизма бедного человека со следующим типом данных:
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
вместе с соответствующими реализациями дают наибольшее понимание в этом вопросе.