Тип ошибки при попытке реализовать функцию (>> =), чтобы создать пользовательский монадский трансформатор
-
27-09-2019 - |
Вопрос
Я пытаюсь создать монадский трансформатор для будущего проекта, но, к сожалению, моя реализация функции Monad TypeClasse (>> =) не работает.
Прежде всего, вот основной монадской реализации:
newtype Runtime a = R {
unR :: State EInfo a
} deriving (Monad)
Здесь реализация Monad TypeClasse осуществляется автоматически GHC (используя GeneralizedNewtypeDeriving
Языковая прагма). Монадский трансформатор определяется как:
newtype RuntimeT m a = RuntimeT {
runRuntimeT :: m (Runtime a)
}
Проблема приходит от того, как я указываю функцию (>> =) функции монады TypeClasse:
instance (Monad m) => Monad (RuntimeT m) where
return a = RuntimeT $ (return . return) a
x >>= f = runRuntimeT x >>= id >>= f
Как я вижу это, первый >>=
бежит в основе базового m
монад Таким образом, runRuntimeT x >>=
Возвращает значение типа Runtime a
(правильно ?). Затем следующий код, id >>=
, должен вернуть значение типа a
. Отказ Это значение передается на функцию f тип типа f :: (Monad m) => a -> RuntimeT m b
.
И вот поставляется проблема типа: f
Тип функции не соответствует типу, требуемую функцией (>> =). JOW Могу ли я сделать это согласованность? Я вижу, почему это не работает, но мне не удалось превратить его во что-то функциональное.
Редактировать: сообщение об ошибке:
Core.hs:34:4:
Occurs check: cannot construct the infinite type: m = RuntimeT m
When generalising the type(s) for `>>='
In the instance declaration for `Monad (RuntimeT m)'
Failed, modules loaded: none.
Спасибо, что вы помогите, и не стесняйтесь исправлять любые недостатки в моем сообщении,
Чарли П.
Решение
Следовать от того, что Рейд Бартон сказал о StateT
- вот как вы бы определили RuntimeT
с использованием StateT
. Отказ То Runtime
Затем Монад может быть тривециально определен с использованием личности монада.
newtype RuntimeT m a = R {
unR :: StateT EInfo m a
}
type Runtime = RuntimeT Identity
instance Monad m => Monad (RuntimeT m) where
return = R . return
(R m) >>= f = R (m >>= unR . f)
Другие советы
Обычно StateT s m
Монад отправляет a
к s -> m (a, s)
Но вы работаете с m (s -> (a, s))
вместо. Я не думаю, что последние формируют монад для общего s
. Отказ Вы уверены, что вы не просто хотите использовать StateT
?
Вот почему я не думаю a
→ m (s -> (a, s))
это монад: писать >>=
Мне нужна функция, которая принимает аргументы типов
m (s -> (a, s))
a -> m (s -> (b, s))
и возвращает значение типа
m (s -> (b, s))
«Эффекты» (т.е. fmap (const ())
) результата должны быть те из первого аргумента, поскольку у нас нет возможности получить a
перейти ко второму аргументу. С m
появляется только снаружи типа результата, мы тогда не можем использовать второй аргумент для чего-либо вообще - не будет способа избавиться от m
это вводит.