At 08.48 -0300 0-09-23, Jaci Junior wrote:
> Dear reader, Is there a function that takes an "IO String" and
>make it into String?
To have a function IO(String) -> String would contradict the very idea of
Haskell being a pure language: IO isn't pure, so if such a conversion
function was available, it would be possible to have impure IO-functions
without an IO attached to their type. So once you have put in an IO
somewhere, you are stuck with it.
This is not much of a problem though, because Haskell uses monads to
describe IO, and one way to characterize monads is that these are objects
that have the ability to always extend regular code to the code of the type
the monad describes. So regular code can always be converted into IO code,
using the monad properties. The simplest way to think about the IO monad is
perhaps that this is a way to tell the Haskell type system that IO is
taking place in the functions in question.
Monads do not commute, for example creating lists can also be thought of as
being a monad (the monoid monad). Then IO([a]) is an IO involving a list
object, whereas [IO(a)] is a list of potential IO actions.
If you have an object
x :: IO String
then you can use it as though it was a string by
do { s <- x; ... } -- s will be of type String.
Alternatively, you can pipe IO objects by
x >> y -- y does not use output from x
x >>= y -- y uses output from x
return s -- if value returned is not already IO, put in a "return".
In fact, a monad M is (mathematically) a triple (F, iota, mu), where F is
an endo-functor of a category C, and "iota" and "mu" are natural
transformations of this category to itself. Here, "iota" is called the unit
and "mu" the multiplication of the monad, named so because in the
endo-category End(C), a monad is just a free monoid, with set F, unit iota,
and multiplication mu.
In the case of the IO monad, iota = return, and mu = (>>=) (or rather a
variation which is a set-theoretic rewrite of the so called Kleisli
multiplication). The IO functor in Haskell is really the type function that
associates the type "a" with IO(a) (not to be confused with "return" which
takes a _values_ and convert them to IO(a) values), plus a function
map :: (a -> b) -> (f a -> f b)
just as in the case of the class Functor in the Prelude (where it is name
"fmap").
Now, if one has the data
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
then one derive the function "map", just as is done in the module Monad,
where it is called "liftM". Thus, the functor part F of the triple M = (F,
iota, mu) can be derived, and in Haskell programming, people tend to forget
about it. The ">>", and "fail" (as well as the "do" construct named above)
are just put in order to simplify programming.
Hans Aberg