The following compiles without PolyKinds
:
{-# LANGUAGE TypeFamilies, GADTs #-}
type family Modulus zq
type family Foo zq q
data Bar :: (* -> *) where
Bar :: (zq' ~ Foo zq (Modulus zq)) => Bar (zq -> zq')
All appearances of zq
are some type (kind *
) representing modular arithmetic mod q
. It'd be convenient to use Nats
to represent these moduli. If I add PolyKinds
and poly-kind the moduli in the type families:
{-# LANGUAGE TypeFamilies, GADTs, PolyKinds #-}
type family Modulus zq :: k
type family Foo zq (q :: k)
data Bar :: (* -> *) where
Bar :: (zq' ~ Foo zq (Modulus zq)) => Bar (zq -> zq')
GHC 7.8 complains:
Could not deduce (zq' ~ Foo zq (Modulus zq))
...
In the ambiguity check for:
forall zq' zq. zq' ~ Foo zq (Modulus zq) => Bar (zq -> zq')
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the definition of data constructor ‘Bar’
Did adding PolyKinds
really make this ambiguous? Where is the ambiguity? Also related: When is -XAllowAmbiguousTypes appropriate?
If I throw GHC a bone and add AllowAmbiguousTypes
the error moves from the declaration of the GADT to the use of the GADT (sans the suggestion to add the extension):
bar :: (zq' ~ Foo zq (Modulus zq))
=> Bar (zq -> zq')
bar = Bar
which makes me think using AllowAmbiguousTypes
is a GHC red herring.
EDIT
To clarify, the types above might be instantiated as follows:
newtype Zq q = Zq Int
Then zq ~ (Zq 3)
, q ~ 3
, and Modulus (Zq 3) ~ 3
, Foo (Zq 3) 3 ~ (Zq 3)
(I stripped the work out of the Foo
type family, so think of it as identity.)