假设我有一个类型列表{kind [*]
:
let Ts = '[Int, Bool, Char]
我想将其转换为元组链:
type family Tupled (ts :: [*]) z :: *
type instance Tupled (t ': ts) z = (t, Tupled ts z)
type instance Tupled '[] z = z
到目前为止一切顺利:
> :kind! Tupled Ts ()
Tupled Ts () :: *
= (Int, (Bool, (Char, ())))
现在我希望能够编写一个类型Fun
来表示在该链的“底部”具有多态性的函数。例如,Fun Ts Ts
应该适用于以下任何一种类型:
(Int, (Bool, (Char, (String, ()))))
(Int, (Bool, (Char, (Word, (ByteString, ())))))
我试过了:
newtype Fun as bs = Fun
{ unfun :: forall z. Tupled as z -> Tupled bs z }
但它未能进行类型检查:
Couldn't match type ‘Tupled bs z’ with ‘Tupled bs z0’
NB: ‘Tupled’ is a type function, and may not be injective
The type variable ‘z0’ is ambiguous
Expected type: Tupled as z -> Tupled bs z
Actual type: Tupled as z0 -> Tupled bs z0
In the ambiguity check for the type of the constructor ‘Fun’:
Fun :: forall z. Tupled as z -> Tupled bs z
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the definition of data constructor ‘Fun’
In the newtype declaration for ‘Fun’
我见过建议使用数据系列来避免注入性问题:
data family Tupled (ts :: [*]) z :: *
data instance Tupled (t ': ts) z = Cons t (Tupled ts z)
data instance Tupled '[] z = Nil
确实这会使Fun
编译,但是当我想要使用元组时,看起来这会让我“卡在”Cons
和Nil
的土地上这样:
Fun $ \ (i, (b, (c, z))) -> (succ i, (not b, (pred c, z)))
我可以以某种方式解决这个问题吗?
答案 0 :(得分:4)
启用AllowAmbiguousTypes
。从GHC 8开始,歧义检查完全是多余的,因为任何(基本上可解析的)歧义都可以通过类型应用程序来解决。此外,您的情况似乎只是歧义检查的误报,因为我们可以清楚地使用Fun
,即使没有类型的应用程序。