2016-09-09 3 views
0

Скажем у меня есть некоторые Монадические ТипуКак применять пользовательские Монада Transformer

data Example a = CheckIt {unwrap :: a} 

instance Functor Example where 
    fmap f (CheckIt x) = CheckIt (f x) 

instance Applicative Example where 
    pure = CheckIt 
    CheckIt f <*> CheckIt x = CheckIt (f x) 

instance Monad (Example) where 
    return = CheckIt 
    [email protected](CheckIt a) >>= f = f a 

и у меня есть функция, которая возвращает [a] на основе некоторых входных сигналов:

fetchList :: b -> [Int] 
fetchList _ = [1,2,3,4] 

и функцию, которая возвращает IO [a] (упрощенное из реальной реализации):

basicIoWrap :: [a] -> IO [a] 
basicIoWrap x = return x 

и я хочу запустить этот IO, а затем извлечь Пример [а] от него:

Следующая не работает:

foo :: b -> Example [a] 
foo val = (basicIoWrap (fetchList val)) >>= \list -> return list 

жалуется на различные типы монадных

Couldn't match type ‘IO’ with ‘Example’ 
     Expected type: Example [a] 
     Actual type: IO [Int] 

Так что я понимаю, что это именно UseCase для Monad трансформаторов, но Я действительно изо всех сил пытаюсь понять, как применять их в контексте. Скажем, у меня был трансформатор:

newtype ExampleT m a = ExampleT {runExampleT :: m (Example a)} 

и я перефразировал свою подпись Foo :: б -> ExampleT (IO [а])

Я неясно, что тело функции будет выглядеть, и также, как я в конечном итоге извлечу из него пример [a]? Не будет runExampleT ExampleT (IO [a]) дать IO [Example a], таким образом, просто пробивая проблему с несколькими Монадами дальше по дороге?

+1

В дополнение к различным небезопасным функциям «выключения» вы не можете удалить список из монады ввода-вывода, чтобы вернуть «Пример [a]». Причина, по которой трансформатор IoT не существует, заключается в том, что монада IO, если она используется, должна находиться в основе стека, то есть внешняя самая монада любого стека - 'IO'. – chepner

+0

Итак, как это вообще происходит в этой ситуации? –

+1

Монадный трансформатор - это прежде всего добавление поведения к существующей монаде, а не извлечение из нее значений. Если 'foo' возвращает' IO (Пример [a]) '(поскольку @ user2297560 избил меня, чтобы предложить), то относительно легко написать функцию с типом' bar :: Example [a] -> IO [a] 'для извлечения внутреннего списка (сохраняя его в контексте IO). С такой функцией вы можете написать 'foo >> = bar'. – chepner

ответ

2

Вы никогда не можете безопасно «убежать» от IO, но если у вас есть значение типа как Example (IO [a]) и Example по крайней мере Traversable, то вы можете превратить его в IO (Example [a]) с функцией sequence. Используя этот метод, вы можете написать свой foo функцию:

foo :: b -> IO (Example [a]) 
foo = sequence . return . basicIoWrap . fetchList 

Поскольку вы должны уже работать в IO монады для того, чтобы использовать basicIoWrap, вы можете получить доступ к Example [a]. Например:

do input <- getLine 
    (Example as) <- foo input 
    mapM_ print as 
+0

Обратите внимание, что 'Example' нуждается в экземпляре' Traversable', чтобы 'sequence' превратил значение' Example (IO [a]) в значение 'IO (Example [a])'. – chepner

Смежные вопросы