Why doesn't this dollar-sign construct work?

dollar-sign, haskell

Solution

This is a precedence issue. You have two infix operators here, `:` and `$`. As an infix operator, `:` has higher precedence than `$`, so it binds more tightly. You can ask about precedence in ghci

>> :i :
data [] a = ... | a : [a]        -- Defined in `GHC.Types`
infixr 5 :

>> :i $
($) :: (a -> b) -> a -> b
infixr 0 $

The `infixr` means that the operator groups to the right (so that the expression `a + b + c` is interpreted as `a + (b + c)`) and the number gives the precedence (higher = more tightly binding).

Also, you need to know that function application has the highest precedence (tighest binding). So in your two expressions, this one

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

is grouped like

fibs = 0 : (1 : (zipWith (+) fibs (tail fibs)))

whereas this

fibs = 0 : 1 : zipWith (+) fibs $ tail fibs

is grouped like

fibs = (0 : (1 : (zipWith (+) fibs))) $ (tail fibs)

which gives you an error, because the expression to the left of `$` should be a function, but in your case it is a list.

Problem

Yep, another dollar-sign question. I'm sorry... (I used the search function!) My professor for the course functional programming told us that the dollar sign 'kinda adds an opening parenthese and then a closing one at the end' (it's very roughly described here in more or less the same manner). So ``` fibs = 0 : 1 : zipWith (+) fibs $ tail fibs ``` should be equivalent to ``` fibs = 0 : 1 : zipWith (+) fibs (tail fibs) ``` Well, it isn't. The second thing compiles fine, the first thing gives an error: ``` jkjj.hs:1:8: Couldn't match expected type `[a1] -> [a1]' with actual type `[a0]' The first argument of ($) takes one argument, but its type `[a0]' has none In the expression: 0 : 1 : zipWith (+) fibs $ tail fibs In an equation for `fibs': fibs = 0 : 1 : zipWith (+) fibs $ tail fibs fibonacci.hs:1:16: Couldn't match expected type `[a0]' with actual type `[a1] -> [a1]' In the return type of a call of `zipWith' Probable cause: `zipWith' is applied to too few arguments In the second argument of `(:)', namely `zipWith (+) fibs' In the second argument of `(:)', namely `1 : zipWith (+) fibs' ``` And of course, since $ is a function, things like: ``` fibs = 0 : 1 $ zipWith (+) fibs (tail fibs) ``` won't work, so at the very least the explanation my professor gave was an oversimplification. While writing this post, I tried to place the parentheses so that the error would be the same. I got: ``` fibs = (0 : 1 : zipWith (+) fibs) $ tail fibs ``` and fibs = (0 : 1 : zipWith (+) fibs) (tail fibs) which both gave me exactly the same error message (except for the column numbers, of course). Why is this? Is a b $ c d equivalent to (a b) (c d) rather than a b (c d)? I think this all has to do with function precedence and/or associativity, but I don't know the specifics. I don't know how you can see what precedence level a function has (except trying a lot of combinations) and I can't find it with google either. I hope somebody can help me figure this out!

Original source