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
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to