With -XTypeApplications
in GHC 8.0, you can specify types explicitly with @
preceding function arguments. What types does it exactly specify, especially when several @
are introduced?

- 1,879
- 17
- 29
-
1I think it's a good idea to use `ExplicitForAll` (or `TypedScopeVariables` which subsumes it) if you intend to use `TypeApplications`, since in that case there's no ambiguity: if you have e.g. `const :: forall a b. a -> b -> a`, then the first `@`-argument will be for the `a`, and the second one for the `b`. – Cactus Oct 27 '16 at 05:52
-
2`ScopedTypeVariables` – dfeuer Oct 27 '16 at 06:00
1 Answers
If you look at the type of a function
elem :: (Foldable t, Eq a) => a -> t a -> Bool
we see it has two polymorphic variables, t
and a
. These variables are what the @
type applications specify. It seems that variables introduced in the context — where typeclass constraints go — affect order, and hence the first @
specifies the t
, and the second the a
. In functions without context variables
const :: a -> b -> a
the order is more obvious, the a
is first and b
is second. As Cactus mentioned in a comment above, you can also use explicit foralls to specify the order yourself.
myConst :: forall b a. a -> b -> a
Now the first type application will specify the b
and the second the a
.
You may run into this problem of needing to specify types particularly if you're using overloaded strings or lists
elem c "abc...xyz" -- What string type is this?
elem c ['a' .. 'z'] -- What list constructor is this?
therefore we use explicit type applications
elem @[] @Char c ['a' .. 'z']
in this case we only have to specify the @[]
and say "this is a []
list type constructor" because GHC infers Char
from the list elements, so @Char
can be omitted here.
If a polymorphic argument GHC is able to infer happens to come first you can leverage -XPartialTypeSignatures
which allows you to use _
in type signatures including type application signatures, telling GHC to just infer that [part of the] type, to make things less verbose.
f @_ @[]

- 1,879
- 17
- 29
-
4To me it seems that after more than one type application any readability benefit compared to `::` is gone, especially since one has to recall the type constraint order. At least in this case, I'd consider `elem c ['a' .. 'z'] :: [Char]` to be far more readable. – MauganRa May 04 '18 at 10:13