Here's another way of looking at what others have already said. The only way you can do that is within the scope of another IO action. For example:
outputXmlTrees :: IO ()
outputXmlTrees = do
trees <- inputXmlTrees;
let newTrees = transform trees;
print . show $ newTrees
Notice a few things:
- First, the line "trees <- inputXmlTrees" effectively takes an IO [XmlTree] and turns it into a [XmlTrees]. That is, it runs the IO action inputXmlTrees, and gives you the resulting list of XmlTrees to work with.
- You can then pass these off to a pure function which will monkey around with them in a pure (non-IO) context
- You must do this in an IO action, however, and any monadic action gets its type from the last line. Thus, the last line must be of type IO something. In this case, it is simply the action that would print out the trees.
- Thus, this gives you a way to glue together different IO actions and pure actions and combine them into larger IO actions
Hope this clarifies