嵌套元组链上的多态函数

时间:2017-04-14 04:57:00

标签: haskell fold type-level-computation

假设我有一个类型列表{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编译,但是当我想要使用元组时,看起来这会让我“卡在”ConsNil的土地上这样:

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

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

1 个答案:

答案 0 :(得分:4)

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