9

I know

$ :: (a->b) -> a -> b
f $ x = f x

Intuitively it seems to me, like to say, 1. $ delays the evaluation of the function to its left 2. evaluates whats to its right 3. feeds the result of its left to its right.

And it makes perfect sense to me when,

ghci> length $ [1..5]
5
ghci> ($) length [1..5]
5

What I do not understand is why,

ghci> ($ [1..5]) length
5

Judging from the type of $, isn't that its (first) argument should be a function ?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Znatz
  • 1,530
  • 2
  • 18
  • 31
  • 14
    This isn't about `($)`, but about operator sections. – phipsgabler Apr 03 '13 at 10:27
  • 9
    `$` *doesn't* delay evaluation of the function to it's left. You may be confusing it with `$!`, which forces partial evaluation of the argument to its right before feeding it to the function to its left. – dave4420 Apr 03 '13 at 10:28
  • This is "section" syntax at work. http://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-300003.5 – Don Stewart Apr 03 '13 at 10:32
  • 1
    And as to what this is good for: you can use it when you want to apply a list of functions to one value: `map ($ [1..5]) [length,sum,product]`. – phipsgabler Apr 03 '13 at 10:35
  • @dave4420 ``id $! x == x `seq` id x`` doesn't force anything, or so I've been told. – Will Ness Apr 03 '13 at 10:41
  • @WillNess Well, `seq`, or `($!)` are only evaluated when their result is demanded. Since argument and result of `id` are the same, `id $! x` forces the evaluation of the argument, `x`, (to weak head normal form) exactly when the result, `x`, needs to be evaluated (to WHNF). So it's rather hard to determine whether the `($!)` did anything there. But in an implementation where ``a `seq` b`` evaluates `a` before `b` (that is not required by the semantics of `seq`), if you look hard enough, you can see that `id $! undefined` errors before `id` returns. – Daniel Fischer Apr 03 '13 at 17:44
  • @DanielFischer the reason I dwell on this is that I was confused by this quite a few times by assuming that `$!` "forces its argument". The real question, *when?*, is left out by this magical statement. Would it be better to say that `$!` "arranges for its argument to be forced before being fed to the function, when the result of function application is forced"? – Will Ness Apr 03 '13 at 18:36
  • @Will Common confusion. I have of course never suffered from it (_whistles innocently_). The answer is, a function cannot do anything - in particular not force the evaluation of one of its arguments - before it is called. When is it called? When its result needs to be evaluated, no earlier, no later. Regarding your edit, yes, it would probably be better to say `($!)` forces its second argument when its result is needed to be evaluated. – Daniel Fischer Apr 03 '13 at 18:42

3 Answers3

16

This has to do with parsing. In Haskell you can write (op arg) where op is an infix operator. This is not the same as ((op) arg). And you can write (arg op) as well! For example:

GHCi, version 7.0.3: http://www.haskell.org/ghc/  :? for help
Prelude> :t (+ 4)
(+ 4) :: Num a => a -> a
Prelude> :t (4 +)
(4 +) :: Num a => a -> a

That is, (+ 4) is the function \x -> x + 4 and (4 +) is the function \y -> 4 + y. In the case of addition these are equal functions, but that is not really important right now.

Now let us try the same trick on $:

Prelude> :t ($ [1,2,3,4])
($ [1,2,3,4]) :: Num t => ([t] -> b) -> b

Now surprise so far, we got \f -> f $ [1,2,3,4]. We can also write

Prelude> :t (length $)
(length $) :: [a] -> Int

to get the function \l -> length $ l. But how about this:

Prelude> :t ($ length)
($ length) :: (([a] -> Int) -> b) -> b

This is strange, but it makes sense! We got \f -> f $ length, i.e., a functional which expects to get a function f of type ([a] -> Int) -> b) that will be applied to length. There is a fourth possibility:

Prelude> :t ([1,2,3,4] $)

<interactive>:1:2:
    Couldn't match expected type `a0 -> b0' with actual type `[t0]'
    In the first argument of `($)', namely `[1, 2, 3, 4]'
    In the expression: ([1, 2, 3, 4] $)

Everything is as it should be because [1,2,3,4] is not a function. What if we write $ in parenthesis? Then its special meaning as an infix operator disappears:

Prelude> :t (($) length)
(($) length) :: [a] -> Int

Prelude> :t (($) [1,2,3,4])
<interactive>:1:6:
    Couldn't match expected type `a0 -> b0' with actual type `[t0]'
    In the first argument of `($)', namely `[1, 2, 3, 4]'
    In the expression: (($) [1, 2, 3, 4])

Prelude> :t (length ($))
<interactive>:1:9:
    Couldn't match expected type `[a0]'
                with actual type `(a1 -> b0) -> a1 -> b0'
    In the first argument of `length', namely `($)'
    In the expression: (length ($))

Prelude> :t ([1,2,3,4] ($))
<interactive>:1:2:
    The function `[1, 2, 3, 4]' is applied to one argument,
    but its type `[t0]' has none
    In the expression: ([1, 2, 3, 4] ($))

So, to answer your question: $ [1,2,3,4] is parsed as \f -> f $ [1,2,3,4] so it makes perfect sense to apply it to length. However ($) [1, 2, 3, 4] does not make much sense because ($) is not seen as an infix operator.

By the way, $ does "not do anything", so to speak. It is mostly used for more readable input because it has low precedence and so we can write f $ g $ h $ x instead of f (g (h x)).

Andrej Bauer
  • 2,458
  • 17
  • 26
  • 1
    `-` may have been a bad choice of example, as it's the one and only exception where `(op arg)` does *not* represent a function. – Scott Olson Apr 03 '13 at 10:44
  • 1
    Also, both `((-) 4)` and `(4 -)` are the same function, `(\x -> 4 - x)`. – Scott Olson Apr 03 '13 at 10:45
  • Does it mean because (-) is left associated, both ((-) 4) and (4 -) means (\x -> 4 - x), while ($) is right associated, both ($ func) and ($ arg) means (\x -> bar $ a) where a means func or arg ? – Znatz Apr 03 '13 at 11:29
  • Oops, let me fix that. Thanks, Scott. – Andrej Bauer Apr 03 '13 at 11:39
  • 1
    This has nothing to do with associativity. The thing which is confusing @Znatz is that `f $ length` makes sense if `f` has the correct type. Thus Haskell is parsing `$ length` as `\f -> f $ length`, just like `$ [1,2,3,4]` is parsed as `\f -> f $ [1,2,3,4]`. – Andrej Bauer Apr 03 '13 at 11:43
  • OK, I see. `($ length) ((*2).) [1..10]` does give me an expected `20`. However, it is still very confusing that `((-) 4)` is parsed as `(\x -> 4 - x )` but not `(\x -> x - 4)` – Znatz Apr 03 '13 at 13:09
  • 1
    It's because `((-) 4)` isn't an operator section at all. It's just normal partial application of `-`, and it is given its arguments left-or-right like every other function. Since it takes its left argument first, you get `(\x -> 4 - x)`. – Scott Olson Apr 03 '13 at 14:32
10

Your question is really about what is called operator sections. With any operator in Haskell (I will use + as an example) you can write something like (+ arg) or (arg +). These are just shorthand syntax for the anonymous functions (\x -> x + arg) and (\x -> arg + x), respectively.

So, the ($ [1..5]) syntax just means (\x -> x $ [1..5]) which is the same as (\x -> x [1..5]) (ie. a function which passes [1..5] to the function passed as its argument).

Scott Olson
  • 3,513
  • 24
  • 26
6

($ [1..5]) is a section. That's a partially applied operator. It's a shorthand for (\f -> f $ [1..5]).

Sections let you supply one argument to a binary operator and produce a function - a function which is waiting for the remaining argument.

Take a look at http://www.haskell.org/haskellwiki/Section_of_an_infix_operator

drquicksilver
  • 1,627
  • 9
  • 12