I see there's another answer about this but it misses one key point which is likely the cause of your (and WinHugs') confusion.

On 2009 Jan 7, at 19:31, David Schonberger wrote:
listFactorial l = 
 if length l == 0
  then return 1
  else do
   fact (head l)
   listFactorial (tail l)
 
fact n = 
 if n == 0 
  then return 1
  else return foldr (*) 1 [1..n]

"return" doesn't mean what it does in other languages.  It means "wrap this value in a monad".  Since neither of the above functions involves a monad at all, the "return"s confuse Hugs into thinking you're doing something more complex than you actually are (hence the scary-looking type inference).

Ignoring (most) other optimizations to the code, since the other message hit them:

> listFactorial []     = [1]
> listFactorial (x:xs) = fact x : listFactorial xs
>
> fact 0 = 1
> fact n = foldr (*) 1 [1..n]
>
> f = do
>   nums <= askForNums
>   putStr ("Sum is " ++ (show (foldr (+) 0 nums)) ++ "\n")
>   putStr ("Product is " ++ (show (foldr (*) 1 nums)) ++ "\n")
>   print $ listFactorial nums

If you'd rather keep your original definition of "f" and put listFactorial in IO, then:

> listFactorial []     = print 1
> listFactorial (x:xs) = do
>   print $ fact x
>   listFactorial xs

-- 
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com
system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu
electrical and computer engineering, carnegie mellon university    KF8NH