[Haskell-cafe] Noob error: Type b -> c b Does not match IO a

Bernard Pope bjpop at cs.mu.OZ.AU
Thu Jun 23 00:54:26 EDT 2005

On Thu, 2005-06-23 at 00:17 -0400, kynn at panix.com wrote:

> printFact [] = return
> printFact (x:xs) = do  -- triggers error message
>   putStrLn (x ++ " factorial is " ++ fact x)
>   printFact xs
>   return

> If anyone can explain to me how to fix this error I'd appreciate it.

You forgot to return a value. Typically when you have a function which
performs IO, but you don't want to return anything special as its result
you return the unit value, written as: ().

printFact [] = return ()
printFact (x:xs) = do  -- triggers error message
    putStrLn (x ++ " factorial is " ++ fact x)
    printFact xs
    return ()

Another problem with this code is that you are trying to append numbers
with strings: x ++ " factorial is " ++ fact x

You will need to convert the numbers to strings explicitly with show:

   show x ++ " factorial is " ++ show (fact x)

> Also, what is the difference between <- and let?

The key difference is that, in the do notation, <- is used exclusively
with monads, whereas, let can be used with arbitrary types. The left
argument to <- is some kind of pattern (most often just a single
variable), and the right argument is a monadic expression. Eg:

   x <- getLine

means roughly: _run_ getLine, which returns an (IO String) type, and
bind the actual String to x, whatever the String happens to be in this
instance. Note carefully, that getLine has type (IO String) but x
has type String.

The let keyword is just an ordinary polymorphic binding, eg

   let x = 5 + y

says x is equal to the expression "5 + y" from now on, until the end of
the do block, or another binding of x is introduced. Note carefully that
if (5 + y) has type Int (for argument's sake), then x also has type Int.

Note that for let, unlike <-, the right argument is an arbitrary
expression, it does not have to be a monadic one. 

What might be confusing is that you can write:

   let z = getLine

which is not the same as:

   z <- getLine

The former just makes z equal to getLine, the latter _runs_ getLine,
unpacks the IO result, and binds it to z.

You might benefit from looking at how do notation is desugared into
ordinary expressions, this might help demystify some of it. Take a look
at the Haskell Report:


> Lastly, any comments on any other detail of the code, particularly
> coding, style are most welcome.

Once you become familiar with Haskell you will learn that some patterns
are idiomatic and can be simplified with the use of library functions.
For instance, many operations over lists can be achieved with a map, or
a fold. Also there are some useful versions of these for monads, such as
mapM and foldM. Reading other people's code sometimes helps.


More information about the Haskell-Cafe mailing list