Noob error: Type b -> c b Does not match IO a

--text follows this line-- I'm trying to learn Haskell from YAHT. My attempt at a solution of Exercise 3.10 is failing with a "Type does not match" error. The exercise is to write a function that will read numbers (one per line) from the command line, until the number 0 is entered. At this point the program is supposed to print out the sum of the numbers, their product, and for each number, the factorial. The interaction should resemble this: Give me a number (or 0 to stop): 5 Give me a number (or 0 to stop): 8 Give me a number (or 0 to stop): 2 Give me a number (or 0 to stop): 0 The sum is 15 The product is 80 5 factorial is 120 8 factorial is 40320 2 factorial is 2 The code I have for this is given next (the line that fails is indicated by a comment): module Main where import IO main = do hSetBuffering stdin LineBuffering numberList <- getList let s = sumList numberList let p = prodList numberList putStrLn ("The sum is " ++ s) putStrLn ("The product is " ++ p) printFact numberList fact 0 = 1 fact 1 = 1 fact x = x * fact x - 1 sumList [] = 0 sumList (x:xs) = x + sumList xs prodList [] = 1 prodList (0:xs) = 0 prodList (x:xs) = x * prodList xs printFact [] = return printFact (x:xs) = do -- triggers error message putStrLn (x ++ " factorial is " ++ fact x) printFact xs return getList = do putStrLn "Give me a number (or 0 to stop):" numString <- getLine let num = read numString if num == 0 then return [] else return (num:getList) Here's the full error I get (from HUGS): IO> :l Ex3_10 ERROR "./Ex3_10.hs":28 - Type error in generator *** Term : printFact xs *** Type : b -> c b *** Does not match : IO a If anyone can explain to me how to fix this error I'd appreciate it. Also, what is the difference between <- and let? Lastly, any comments on any other detail of the code, particularly coding, style are most welcome. Thanks! kj

On Thu, 2005-06-23 at 00:17 -0400, kynn@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: http://www.haskell.org/onlinereport/exps.html#sect3.14
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. Cheers, Bernie.

From: Bernard Pope

Hi there, a professor gave us an assigment to make a FA -> RE translator in any language we chose to, i decided to bite the bullet and learn Haskell as have been wanting to for a long time. The code seems to work ok, but i am wondering if someone more knowledgeable could give me advices over how i could have done it better/easier. At many places i have put a Char type instead of an abstract one because some funcations were not working properly before and i wanted to be able to output things and so be able to see what was the problem. (Haskell doesnt seem a 'magic' function to output arbitrary structures? That would be quite helpful for debugging) And probably it's better style to use $ instead of many parentheses as i did (i didnt know what $ was for at the time...) The name of the file i made was: Fa2RegExp.hs I tried reused all i could find from Joao Saraiva's RE -> FA library. But iirc this was only the data definitions for NDFA, DFA, RE and the DFA->NDFA translator. I am sending all the files attached (Fa2RegExp.hs + the library) Thanks Flavio Botelho

Flavio Botelho wrote:
At many places i have put a Char type instead of an abstract one because some funcations were not working properly before and i wanted to be able to output things and so be able to see what was the problem. (Haskell doesnt seem a 'magic' function to output arbitrary structures? That would be quite helpful for debugging)
The show method in the Show class generates a string representation of
an instance. The print function can be used to print the string
representation of any instance of Show to stdout.
All standard types except for functions are instances of Show, and
Haskell can automatically derive Show instances for user defined
types, provided that all of the constituent types are instances of
Show.
--
Glynn Clements

On 6/23/05, kynn@panix.com
getList = do putStrLn "Give me a number (or 0 to stop):" numString <- getLine let num = read numString if num == 0 then return [] else return (num:getList)
This will give you an error as well. 'num' is of type Integer, whereas getList is of type IO [Integer]. So consing an integer with an IO-action returning a list of integer is a type error. Try something like:
if num == 0 then return [] else do rest <- getList return (num:rest)
So if there are more numbers to be read you _run_ the action getList, retrieve the result, and then return that result with the number you just read in front of it. /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862
participants (5)
-
Bernard Pope
-
Flavio Botelho
-
Glynn Clements
-
kynn@panix.com
-
Sebastian Sylvan