启用 PolyKinds 后,如何给多态函数指定类型签名?

4

启用 PolyKinds 后,之前有效的类型签名可能会变为无效。

以下代码在没有启用 PolyKinds 的情况下可以编译。

{-# LANGUAGE KindSignatures #-}
import GHC.Generics

foo :: Constructor c => t c (f :: * -> *) a -> [Char]
foo = conName

当我启用PolyKinds时,它无法编译。

Kind incompatibility when matching types:
  t0 :: * -> (* -> *) -> * -> *
  t :: * -> (* -> *) -> k -> *
Expected type: t c f a -> [Char]
  Actual type: t0 c f a0 -> [Char]
Relevant bindings include
  foo :: t c f a -> [Char] (bound at Gen.hs:8:1)
In the expression: conName
In an equation for ‘foo’: foo = conName

启用 PolyKinds 后,有没有一种方法来给 foo 指定类型签名?


foo :: Constructor c => (t :: * -> (* -> *) -> * -> *) c (f :: * -> *) a -> [Char] 这段代码是正常工作的,不是错误或特性。 - user1078763
没错,那也可以行得通,因为种类是从签名中的不同位置推断出来的,所以无论你在哪个类型变量上固定它都没关系。 - Ørjan Johansen
1个回答

4
请注意,这里存在差异。
t0 :: * -> (* -> *) -> * -> *
t :: * -> (* -> *) -> k -> *

换句话说,在其中一个签名中,GHC认为第三个参数的类型应该是*,而在另一个中认为它应该具有多态类型k
我认为前者(带有*)来自conName,而后者带有k是因为现在您已启用了PolyKinds,所有可能时都会对所有类型签名进行解析。此外,按设计,签名被认为是函数的完整“API”,这意味着当您明确指定签名时,不会尝试从函数的其余部分推导类型。
在您的签名中,t类型的第三个参数是a,因此您可以通过添加一种注释来修复它,以使其与conName所需的内容保持一致:
foo :: Constructor c => t c (f :: * -> *) (a :: *) -> [Char]
foo = conName

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接