Ошибка типа при попытке реализовать функцию (>> =) для создания собственного преобразователя монад - PullRequest
3 голосов
/ 18 апреля 2010

Я пытаюсь создать преобразователь монад для будущего проекта, но, к сожалению, моя реализация функции типа монад (>> =) не работает.

Прежде всего, вот реализация базовой монады:

newtype Runtime a = R { 
  unR :: State EInfo a
} deriving (Monad)

Здесь реализация типа Монады осуществляется GHC автоматически (с использованием языковой прагмы GeneralizedNewtypeDeriving). Монадный трансформатор определяется так:

newtype RuntimeT m a = RuntimeT {
  runRuntimeT :: m (Runtime a)
} 

Проблема возникает из-за того, что я инстанцирую (>> =) функцию типа монады:

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 не соответствует типу, требуемому функцией (>> =). Как я могу сделать это связным? Я понимаю, почему это не работает, но мне не удается превратить это во что-то функциональное.

Редактировать: Сообщение об ошибке:

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.

Спасибо за вашу помощь, и не стесняйтесь исправлять любые недостатки в моем сообщении,
Чарли П.

Ответы [ 2 ]

4 голосов
/ 18 апреля 2010

Обычная StateT s m монада отправляет a на s -> m (a, s), но вместо этого вы работаете с m (s -> (a, s)). Я не думаю, что последний образует монаду для общего s. Вы уверены, что не хотите просто использовать StateT?


Вот почему я не думаю a & rarr; m (s -> (a, s)) является монадой: для записи >>= мне нужна функция, которая принимает аргументы типов

m (s -> (a, s))
a -> m (s -> (b, s))

и возвращает значение типа

m (s -> (b, s))

«Эффекты» (т.е. fmap (const ())) результата должны быть такими же, как у первого аргумента, поскольку у нас нет способа получить a для передачи второму аргументу. Поскольку m появляется только снаружи от типа результата, мы вообще не можем использовать второй аргумент ни для чего - не будет никакого способа избавиться от введенного m.

3 голосов
/ 19 апреля 2010

Чтобы продолжить из сказанного Рейдом Бартоном о 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)
...