[Haskell-cafe] Converting IO [XmlTree] to [XmlTree]
Jake McArthur
jake.mcarthur at gmail.com
Tue Apr 14 12:11:50 EDT 2009
rodrigo.bonifacio wrote:
> I guess this is a very simple question. How can I convert IO [XmlTree]
> to just a list of XmlTree?
You can't, unless you use `unsafePeformIO`, as others have already
pointed out. Yet others have, more "correctly," suggested that you use
do notation to bind a variable with the type you expect. I want to go
into a little more detail .I have a spontaneous Monad tutorial to throw
out, I guess.
How you can convert a value of type `IO [XmlTree]` is probably the wrong
question. The right question is how you can convert a function of type
`[XmlTree] -> A` into a function of type `IO [XmlTree] -> IO A`. The
correct answer has many names:
fmap, liftA, liftM, (<$>) :: Monad m => (a -> b) -> (m a -> m b)
I will use `fmap` to mean any of the above names. In your case, applying
fmap to a function foo:
foo :: [XmlTree] -> A
fmap foo :: IO [XmlTree] -> IO A
So any time you need to pass an IO value to a pure function, this is one
way to do it.
Suppose that the function actually returns an IO value, though. Here, we
will call the function `bar`:
bar :: [XmlTree] -> IO A
fmap bar :: IO [XmlTree] -> IO (IO A)
Now we seem to be in a similar situation as before. We have an extra IO
that we don't want. There is a function for this:
join :: Monad m => m (m a) -> m a
So, we can use `join` to transform an expression of type `IO (IO a)` to
an expression of type `IO a`. Putting it all together:
bar :: [XmlTree] -> IO A
fmap bar :: IO [XmlTree] -> IO (IO A)
join . fmap bar :: IO [XmlTree] -> IO A
And we now have a sensible function again.
Of course, this is a common pattern, using `join` and `fmap` together,
so we have yet another function:
(=<<) :: Monad m => (a -> m b) -> (m a -> m b)
(Note that this has a different argument order than (>>=). I prefer this
form since it emphasizes that it actually transforms a function.)
So, now we have
bar :: [XmlTree] -> IO A
(bar =<<) :: IO [XmlTree] -> IO A
Putting it all together, with a function that gives us the `IO [XmlTree]`:
xmlTree :: IO [XmlTree]
bar :: [XmlTree] -> IO A
bar =<< XmlTree :: IO A
And that last line is equivalent to this in do notation:
do tree <- xmlTree
bar tree
If you have any questions, please do ask. I understand that it can
appear quite dense to a beginner. I'm thinking about using this approach
in a blog article, which would have more detail and examples, but I
would like to be aware of potential stumbling blocks.
- Jake
More information about the Haskell-Cafe
mailing list