How to apply a custom Monad Transformer
Say I have some Monadic type
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
e@(CheckIt a) >>= f = f a
and I have a function which returns an [a] based on some input:
fetchList :: b -> [Int]
fetchList _ = [1,2,3,4]
and a function that returns an IO [a] (simplified from real implementation):
basicIoWrap :: [a] -> IO [a]
basicIoWrap x = return x
and I wish to run this IO and then extract an Example [a] from it:
The following does not work:
foo :: b -> Example [a]
foo val = (basicIoWrap (fetchList val)) >>= list -> return list
complaining about different monad types
Couldn't match type ‘IO’ with ‘Example’
Expected type: Example [a]
Actual type: IO [Int]
So I understand that this is exactly the usecase for Monad transformers, but I am really struggling figuring out how to apply them in context. Say I had a transformer:
newtype ExampleT m a = ExampleT {runExampleT :: m (Example a)}
and I rephrased my signature to foo :: b -> ExampleT (IO [a])
I am unclear what the function body would then look like, and also, how I would eventually extract an Example [a] from this? Wouldn't runExampleT ExampleT (IO [a]) give an IO [Example a] , thus simply punting the multi Monad problem further down the road?
You can never safely "escape" from IO , but if you have a value of a type like Example (IO [a]) and Example is at least a Traversable , then you can turn it into IO (Example [a]) with the sequence function. Using this method you could write your foo function as:
foo :: b -> IO (Example [a])
foo = sequence . return . basicIoWrap . fetchList
Since you must already be working in the IO monad in order to use basicIoWrap , you can access the Example [a] . For example:
do input <- getLine
(Example as) <- foo input
mapM_ print as
链接地址: http://www.djcxy.com/p/77370.html
上一篇: Monad变形金刚电梯
