定义类型同义词 (GHC) 的类型同义词时出现奇怪的错误

Weird Error When Defining a Type Synonym of a Type Synonym (GHC)

背景

我在 Haskell (GHC) 中编写了以下代码:

{-# LANGUAGE 
  NoImplicitPrelude,
  TypeInType, PolyKinds, DataKinds,
  ScopedTypeVariables,
  TypeFamilies
#-}

import Data.Kind(Type)

data PolyType k (t :: k)

type Wrap (t :: k) = PolyType k t
type Unwrap pt = (GetType pt :: GetKind pt)

type family GetType (pt :: Type) :: k where
  GetType (PolyType k t) = t

type family GetKind (pt :: Type) :: Type where
  GetKind (PolyType k t) = k

这段代码的目的是允许我将任意种类的类型包装成单一种类(即Type)的类型(即PolyType),然后反转过程(即打开包装)稍后。

问题

我想为 Unwrap 定义一个类似于以下内容的类型同义词:

type UnwrapSynonym pt = Unwrap pt

但是,上述定义会产生以下错误(GHC 8.4.3):

* Invalid declaration for `UnwrapSynonym'; you must explicitly
  declare which variables are dependent on which others.
  Inferred variable kinds: pt :: *
* In the type synonym declaration for `UnwrapSynonym'

这个错误是什么意思?有没有办法绕过它来定义 UnwrapSynonym?

我一直在做什么

到目前为止,我解决这个问题的方法基本上是手动内联 Uwrap 我想定义的任何 high-order 类型的同义词,但这感觉很糟糕,我希望有更好的方法.

不幸的是,我对 GHC 的内部工作原理还不够了解,甚至不了解问题所在,更不用说解决问题了。

我相信我对我正在使用的扩展程序(例如 TypeInTypePolyKinds)的工作方式有很好的理解,但显然还不够深入,无法理解这个错误。此外,我无法找到解决类似问题的资源。部分原因是我不知道如何简洁地描述它,这也导致很难为这个问题想出一个好的标题。

这个错误是相当迟钝的,但我认为它想说的是 GHC 已经注意到 UnwrapSynonym 的类型是依赖的,forall (pt :: Type) -> GetKind pt,它希望你明确地注释依赖:

type UnwrapSynonym pt = (Unwrap pt :: GetKind pt)

之所以要告诉它 "which variables are dependent on which others" 是因为这个错误也可能会弹出,例如这种情况:

data Nat = Z | S Nat
data Fin :: Nat -> Type where
  FZ :: Fin (S n)
  FS :: Fin n -> Fin (S n)

type family ToNat (n :: Nat) (x :: Fin n) :: Nat where
  ToNat (S n) FZ = Z
  ToNat (S n) (FS x) = S (ToNat n x)

type ToNatAgain n x = ToNat n x -- similar error

ToNatAgain应该有种类forall (n :: Nat) -> Fin n -> Nat,但是变量x的类型取决于变量n的类型。 GHC 希望对其进行显式注释,因此它告诉我告诉它哪些变量依赖于哪些其他变量,并且它为我提供了它推断出的变量类型以帮助实现这一点。

type ToNatAgain (n :: Nat) (x :: Fin n) = ToNat n x

在你的例子中,依赖关系在 return 类型和参数类型之间。根本原因是相同的,但错误消息显然不是根据您的情况设计的,并且不适合。您应该提交错误报告。

顺便说一句,您真的需要单独的 UnwrapGetType 吗?为什么不让 GetType 依赖?

type family GetType (pt :: Type) :: GetKind pt where
  GetType (PolyType k t) = t