It occurred to me that the $ operator in Haskell is often seen as low-priority function application:
($) :: (a -> b) -> a -> b f $ x = f x
But looking closely at the type, it just occurred to me that you can equally well see the $ operator as the identitify function on function types, because the type can be read as:
($) :: (a -> b) -> (a -> b) ($) = id
So if ($) is
id, why do we need a more restrictive type? Maybe this will work too:
($) :: a -> a ($) = id
> head $ [1..] 1 > (5 $) 5 > map ($ 5) [(+ 1), (* 2)] [6,10] > map (`id` 5) [(+ 1), (* 2)] [6,10]
This still leaves the question of why ($) has a type more restrictive than ‘necessary’. What good could it do? I had a small discussion about this on #haskell. We came up with the following explanations:
- Vixey suggested $’s current type documents its most common use better.
- Heffalump suggested the restrictive type might lead to better quality error messages — though we couldn’t find any good examples of this. Do you know of any?
- Maybe $’s current type makes it easier to optimize.
If you have any answers, I’d love to hear them.
Similarly, I was surprised recently to learn that (.) is just fmap for the reader (aka ((->) e)) monad. I assume that the first and second proposed reasons (better documentation, possibly better error messages in some cases) are the reasons for the more restrictive type for (.) :: (b -> c) -> (a -> b) -> (a -> c) as well.
Leave a comment!
Martijn loves to receive comments! Add yours by filling out the fields below.