[Haskell-beginners] How to unnest "do"
Martin Drautzburg
Martin.Drautzburg at web.de
Sun Jan 27 23:29:18 CET 2013
On Sunday, 27. January 2013 20:43:58 Ertugrul Söylemez wrote:
> Hi there Martin,
>
> since the nested 'do' makes sense, there is little you can do about it.
> However, you can make the code more beautiful and restructure it a bit.
> This is how I would have written it:
>
> import Control.Applicative
> import System.Environment
> import System.IO
>
> stats :: String -> String
> stats =
> unwords .
> sequence [show . length . words,
> show . length . lines,
> show . length]
>
> main :: IO ()
> main = do
> args <- getArgs
> case args of
> [fn] -> fmap stats (readFile fn) >>= putStrLn --<----
> _ -> hPutStrLn stderr "Usage: wc FNAME"
>
> This improves the statistics code slightly, but uses some monadic
> machinery you may not be familiar with.
Thanks, this looks much nicer and is very inspiring.
But let me see if I get this correctly:
readFile fn returns IO String
I cannot see the String itself, but I can map the stats function over it,
which gives me anoter IO String. This works, because every Monad is also a
functor. Another way of looking at this is that fmap lifts the String->String
function "stats" to (IO String) -> (IO String),
Again I cannot see the String inside the IO String, but I can pass it to a
function String->IO String, using (>>=) and putStrLn is such a function, which
also does what I need.
I cannot use the same fmap mechanism ("fmap putStrLn"), because putStrLn is
already String -> IO String and fmap would lift both sides of "->".
I tried to find another way of passing the IO String to putStrLn, but there
aren't many options. If I want to use putStrLn, then I need to get the String
out of the IO String. AFAICS (>>=) is the only way to do this (other than do
notation). In contrast to fmap, (>>=) lifts only the left side.
For the hell of it, I tried to replace putStrLn by a String -> Maybe String
function. This does not work and it made me realize, that the signature of
(>>=) :: m a -> (a-> m b) -> m b demands that the the Monad "m" is the same
all the way through, and only its type parameter can change.
And the Applicative import is not really needed.
Is this about correct?
When I have a program, which accesses stdin and stdout and a database, I
suppose I will have to do things like this a lot?
Sorry for the long post, but I am getting kindof excieted.
More information about the Beginners
mailing list