0

I'm studying the Writer monad and have the following:

myFunction :: Int -> Int -> Writer String Int
myFunction e1 e2 
   | e1 > e2 = do
      tell ("E1 greater")
      return (e1)
   | otherwise = do
      tell ("E2 greater")
      return (e2)

main = do
-- execWriter :: Writer w a -> w 
   print $ execWriter . myFunction 1 2 

Error:

"Couldn't match type ‘WriterT String Data.Functor.Identity.Identity Int’with ‘a0 -> Writer c0 a1’
  Expected type: a0 -> Writer c0 a1
    Actual type: Writer String Int"

Why does this computation error with . and not $? Perhaps my understanding of function composition is incorrect?

Babra Cunningham
  • 2,949
  • 1
  • 23
  • 50
  • well the `(.) :: (b -> c) -> (a -> b) -> a -> c` operator expects two functions each taking one argument and the right one `myFunction` here has no argument (or at least not the one) that `execWriter` is expecting. – Willem Van Onsem Feb 08 '17 at 10:49
  • You can also define `(.:) = (.) . (.)` and then use, `execWriter .: myFunction $ 1 2`. It is also known as the "owl operator". (`(.:)` is already defined in `Data.Composition` - http://hackage.haskell.org/package/composition-1.0.2.1/docs/Data-Composition.html) – zeronone Feb 08 '17 at 11:55

2 Answers2

4

Function composition with . means that the resulting composition will receive an argument.

This portion:

execWriter . myFunction 1 2

Can be written more explicitly like this:

(\x -> execWriter (myFunction 1 2 x))

Since myFunction only takes two arguments, you are getting a compile error.

Had you used $ in your code, like this:

execWriter $ myFunction 1 2

The resulting code expanded is equivalent to this:

execWriter (myFunction 1 2)

Which is valid.

Chad Gilbert
  • 36,115
  • 4
  • 89
  • 97
2

In addition to what Chad said, this happens because regular function application (without using $) has a higher priority than all operators (infix functions), including ..

Your example would have worked if you had written it like this:

(execWriter . myFunction 1) 2

Which is equivalent to:

(\x -> execWriter (myFunction 1 x)) 2

Which then evaluates to:

execWriter (myFunction 1 2)
Teo Klestrup Röijezon
  • 5,097
  • 3
  • 29
  • 37