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变形金刚电梯