嵌套元组链上的多态函数

Polymorphic functions over chains of nested tuples

假设我有一个类型列表,类型 [*]:

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 可以编译,但看起来这让我在 ConsNil 的土地上“卡住了”,当我想要使用元组时,像这样:

Fun $ \ (i, (b, (c, z))) -> (succ i, (not b, (pred c, z)))

我能以某种方式解决这个问题吗?

启用AllowAmbiguousTypes。从 GHC 8 开始,歧义检查是完全多余的,因为任何(基本可解决的)歧义都可以通过类型应用程序解决。此外,您的案例似乎只是歧义检查的误报,因为即使没有类型应用程序,我们也可以清楚地使用 Fun