Haskell PolyKinds 扩展和类型系列

Haskell PolyKinds extension and type families

我在 Haskell 中研究类型族以更深入地了解这个主题,并尝试同时使用多态类型和类型族。

例如,文件的开头有以下语言扩展名(文件中的扩展名比此处显示的更多):

{-# LANGUAGE TypeFamilies,
StandaloneKindSignatures,
RankNTypes,
PolyKinds,
DataKinds,
TypeOperators,
TypeApplications,
KindSignatures,
ScopedTypeVariables,
UndecidableInstances,
MultiParamTypeClasses,
AllowAmbiguousTypes #-}

然后我在类型声明中使用多态类型:

data Proxy (a :: k) = Proxy

效果很好。但当时我试图在定义更丰富的类型族中使用它们:

type family PK (a :: k) :: Type where
  PK Int = Char

GHC 抛出错误:

• Expected kind ‘k’, but ‘Int’ has kind ‘*’
• In the first argument of ‘PK’, namely ‘Int’
  In the type family declaration for ‘PK’.

有解决办法吗? GHC 版本为 8.10.7。提前感谢您的任何想法和帮助。

我推荐你使用StandaloneKindSignatures:

..
{-# Language StandaloneKindSignatures #-}

type Id :: k -> k
type Id a = a

type Proxy :: k -> Type
data Proxy a = Proxy

type
  PK :: k -> Type
type family
  PK a where
  PK Int = Char

kind 参数是不可见的,但您可以在类型族 PK @Type Int = Char 中显式写入它(需要 TypeApplications)。

使用 GADT,您可以编写 Proxy

type Proxy :: k -> Type
data Proxy a where
  Proxy :: Proxy @k a

有人提议在声明标题中允许可见(种类)应用程序:

type Id :: k -> k
type Id @k a = a

type Proxy :: k -> Type
data Proxy @k a = Proxy

type
  PK :: k -> Type
type family
  PK @k    a where
  PK @Type Int = Char

而且我们可以使用 forall-> 类型的“可见相关量化”而不是(隐式)不可见 forall.


type Id :: forall k -> k -> k
type Id k a = a

type Proxy :: forall k -> k -> Type
data Proxy k a = Proxy

type
  PK :: forall k -> k -> Type
type family
  PK k    a where
  PK Type Int = Char

Proxy 之间的区别,定义为统一数据类型(non-GADT 或 tongue-in-cheek:'legacy' 语法)或 GADT。除了 k

之外,它们是等效的(在旧的 GHC 8.10 上测试过)
  • (forall.) specified = 可以用TypeApplications指定,但如果不指定则自动推断
  • (forall{}.) inferred = TypeApplications 略过,不能直接指定

这适用于类型构造函数 Proxy 和名为 P 的数据构造函数以消除歧义,因为它们都是多态的。 Proxy 可以指定 Proxy @Nat 42 或推断 Proxy 42 取决于 k 的量化:

Proxy :: forall (k :: Type). k -> Type
-- or
Proxy :: forall {k :: Type}. k -> Type

并且根据 P 中的量化,k 可以指定 P @Nat @42 或推断 P @42:

P :: forall {k :: Type} (a :: k). Proxy @k a
P :: forall {k :: Type} (a :: k). Proxy    a
-- or
P :: forall (k :: Type) (a :: k). Proxy @k a
P :: forall (k :: Type) (a :: k). Proxy    a

这给出了几个结果

  • k 在两者中推断:P @42 :: Proxy 42 (P @42 :: Proxy 42)
data Proxy a = P
--
data Proxy a where
 P :: Proxy a
  • kProxy 中指定但在 P 中推断 (P @42 :: Proxy @Nat 42)
data Proxy (a :: k) where
 P :: Proxy a
--
type Proxy :: k -> Type
data Proxy a where
  P :: Proxy a
  • kProxyP 中指定 (P @Nat @42 :: Proxy @Nat 42)
data Proxy (a :: k) = P
--
type Proxy :: k -> Type
data Proxy a = P
--
type Proxy :: forall k. k -> Type
data Proxy a = P
--
type Proxy :: forall k. k -> Type
data Proxy (a :: k) = P
--
type Proxy :: k -> Type
data Proxy a where
 P :: Proxy @k a

我正在等待关于量化和范围界定的许多新的和即将发生的变化尘埃落定,这可能已经过时了。

您还差一种语言扩展。如果您也启用了 CUSKs 扩展,那么您所写的内容将如您所愿。