Reputation: 273
I have an expression:
gcastWith p1 $
gcastWith p2 $
e
That works ok. Now I am trying to rewrite it as:
((gcastWith p1) .
(gcastWith p2)) $
e
And it doesn't work (doesn't typecheck). However this works:
((gcastWith p1) .
(gcastWith p2)) -- note I removed the dollar
e
Am I missing something obvious about how $
and .
operate?
Upvotes: 3
Views: 102
Reputation: 116174
I guess it's some restrictions caused by how type inference works. In basic Hindley-Milner types like
f :: (forall a. G a) -> T
are forbidden. GHC Haskell allows them (with suitable extensions turned on), but still uses the HM restriction requiring that a type variable can never be instantiated to a polytype.
This causes some surprise: f e
type checks but f $ e
fails since the type variables in the type of $
should be instantiated to a polytype.
e :: forall a. G a
f :: (forall a. G a) -> T
f e :: T
($) :: (b -> c) -> b -> c
Type checking ($) f e:
b ~ (forall a. G a) -- forbidden polytype!
c ~ T
Since f $ e
is very common in Haskell, and we really want things like runST $ do ....
to work, the GHC devs have added a special-case typing rule for $
. Essentially, when fully applied, f $ e
is typed like f e
.
There is no such special case in the typing system for f . g . h $ e
at the moment. This can make it fail when f $ g $ h $ e
works fine.
Upvotes: 7