2

I have these two expressions:

  1. foldr (-) 0 . map (uncurry (*)) $ coords 5 7

  2. foldr (-) 0 . map (uncurry (*)) (coords 5 7)

The (1) works print out the result, but (2) have error says:

<interactive>:50:15:
    Couldn't match expected type ‘a -> t0 c’
                with actual type ‘[Integer]’
    Relevant bindings include
      it :: a -> c (bound at <interactive>:50:1)
    Possible cause: ‘map’ is applied to too many arguments
    In the second argument of ‘(.)’, namely
      ‘map (uncurry (*)) (coords 5 7)’
    In the expression: foldr (-) 0 . map (uncurry (*)) (coords 5 7)

Can any one tell me what's the difference between these two? Thanks.

duplode
  • 33,731
  • 7
  • 79
  • 150
linjunshi
  • 87
  • 6

3 Answers3

3
foldr (-) 0 . map (uncurry (*)) $ coords 5 7
-- is equivalent to
( foldr (-) 0 . map (uncurry (*)) )  (coords 5 7)
-- and to
foldr (-) 0 ( map (uncurry (*)) (coords 5 7) )


foldr (-) 0 . map (uncurry (*)) (coords 5 7)
-- is equivalent to
foldr (-) 0 . ( map (uncurry (*)) (coords 5 7) )
-- and to
\x -> foldr (-) 0 ( map (uncurry (*)) (coords 5 7) x)

In the latter, the result of map (uncurry (*)) (coords 5 7) is passed to . as its second argument, but it's a list, not a function, so a type error arises.

Note that is is also OK:

foldr (-) 0 $ map (uncurry (*)) (coords 5 7)
chi
  • 111,837
  • 3
  • 133
  • 218
3

There's an easier example:

Prelude> id . id $ "Example"
"Example"
Prelude> id . id ("Example")
<interactive>:2:10:
    Couldn't match expected type ‘a -> c’ with actual type ‘[Char]’
    Relevant bindings include it :: a -> c (bound at <interactive>:2:1)
    In the first argument of ‘id’, namely ‘("Example")’
    In the second argument of ‘(.)’, namely ‘id ("Example")’
    In the expression: id . id ("Example")

The problem is that function application binds stronger than (.). The fixity level of ($) fixes this:

id . id $ "Example" = (id . id) $ "Example"
                    = (id . id) "Example"

However, with (...), the function application wins and you end up using (.) with a non-function as second argument:

id . id ("Example") = id . id "Example"
                    = id . (id "Example") -- apply id
                    = id . ("Example")
                    = type error, since "Example" isn't a function
Zeta
  • 103,620
  • 13
  • 194
  • 236
  • I see now, thanks, I am wondering why (uncurry (*)) ) as a argument with a () didn't cause the problem but the last argument (coords 5 7) did? and btw, what if there are multiple $ in the expression? How would the interpreter interpret the expression? – linjunshi Jul 16 '16 at 09:33
2

$ is simply a no-op in infix form. Because it's an infix operator with low fixity:

GHCi> :i $
($) :: (a -> b) -> a -> b   -- Defined in ‘GHC.Base’
infixr 0 $

any expression in which it occurs is parsed as if it had parenthesis. In your example,

foldr (-) 0 . map (uncurry (*)) $ coords 5 7

is parsed as

  (   (foldr (-) 0)
    . (map (uncurry (*))) )
$ (coords 5 7)

because $ has lower fixity than .. This works in exactly the same way as if you write 1 + 2 * 3: this is parsed as (1) + (2*3), because * has higher fixity than +.

When the $ operator is then evaluated, all it does is apply the function on the LHS – in you case, this is foldr (-) 0 . map (uncurry (*)) – to the RHS expression coords 5 7. Applying a function to its argument is of course also exactly what happens if you just wrote function (argument), however you need to specify the correct function! To write you example without $, you must group it as

( foldr (-) 0 . map (uncurry (*)) ) (coords 5 7)

whereas your attempt is parsed differently: function application binds more tightly than any infix, even ., so your attempt is equivalent to

foldr (-) 0 . ( map (uncurry (*)) (coords 5 7) )

which doesn't make sense.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319