1

Although I feel like a have a good understanding of Haskel IO and Monads, I am having a hard time understanding the following error message.

Consider the following simple function in Haskell

testf :: Show a => a -> String
testf x = show x

I tried implementing a variant that prints to the console by using an IO Monad

printtoscreen :: Show a => a -> IO()
printtoscreen x = putStrLn . show x

However, this yields the following error:

Couldn't match type ‘[Char]’ with ‘a0 -> String’ Expected type: a0 -> String Actual type: String

The correct version should omit explicitly stating the x parameter

printtoscreen :: Show a => a -> IO()
printtoscreen = putStrLn . show

I understand why the last code snippet works, but I cannot make sense out of the error message of the second code snippet, considering that it will also return a string to putStrLn

So why should the xparameter be omitted in the IO() variant?

jdfauw
  • 647
  • 3
  • 11
  • 22
  • 3
    `putStrLn . show x` means `\y -> putStrLn (show x y)`, so you implemented a function with `printtoscreen x y = putStrLn (show x y)`. This thus means that `show` should have type `Show a => a -> b -> String`, but of course the type is `Show a => a -> String`. – Willem Van Onsem Jan 08 '20 at 13:19
  • makes sense, `putStrLn (show x)` indeed does the trick! Thanks a lot, turns out the mistake is out of the scope of IO Monads – jdfauw Jan 08 '20 at 13:22
  • 1
    The issue here is that `putStrLn . show x` is parsed as `putStrLn . (show x)` instead of `(putStrLn . show) x`. This is because function application `show x` has the highest precedence than any binary operator: that's what makes `1 + f x` correct without additional parentheses. – chi Jan 08 '20 at 13:38
  • Probably not strictly a duplicate, but reading the answers [here](https://stackoverflow.com/questions/940382/what-is-the-difference-between-dot-and-dollar-sign) should help you understand better what's going on. – Robin Zigmond Jan 08 '20 at 19:07

2 Answers2

5

., the function composition operator, expects a function. show x however is not a function; it's an evaluated value (of type [Char]) by the time it's given to ..

You'd have to use the function application operator instead:

printtoscreen x = putStrLn $ show x
Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
3

So why should the x parameter be omitted in the IO () variant?

This has nothing to do with IO () itself. You here use function composition. Indeed, the (.) :: (b -> c) -> (a -> b) -> a -> c function is defined as:

(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)

It is thus used to combine two functions f and g in a new function that first applies g to a parameter, and then f to the result of g x.

If you write:

printtoscreen x = putStrLn . show x

then the (.) function will resolve this to:

printtoscreen x = \y -> putStrLn (show x y)

or thus easier to read:

printtoscreen x y = putStrLn (show x y)

This would mean that show should have a type Show a => a -> b -> String, but it has type show :: Show a => a -> String, hence the error.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555