sch*_*kin 5 haskell type-families polykinds
我有两个类型系列,其中一个类型映射一种类型到另一种类型的不同类型和多态函数:
{-# LANGUAGE PolyKinds, TypeFamilies, FlexibleContexts, ScopedTypeVariables #-}
type family F (a :: k1) :: k2
type family G (a :: k2) :: *
f :: forall k1 k2 (a :: k1) (p :: k1 -> *) . p (a :: k1) -> G (F (a :: k1) :: k2)
f = undefined
Run Code Online (Sandbox Code Playgroud)
此代码没有检查以下错误消息:
• Couldn't match type ‘G k20 (F k20 k1 a)’ with ‘G k2 (F k2 k1 a)’
Expected type: p a -> G k2 (F k2 k1 a)
Actual type: p a -> G k20 (F k20 k1 a)
NB: ‘G’ is a non-injective type family
Run Code Online (Sandbox Code Playgroud)
但是我无法理解歧义来自何处以及如何指定缺失的种类?
当我只使用一个类型系列时,它可以工作:
g :: forall k1 k2 (a :: k1) (p :: k1 -> *) (q :: k2 -> *). p (a :: k1) -> q (F (a :: k1) :: k2)
g = undefined
Run Code Online (Sandbox Code Playgroud)
f :: forall k1 k2 (a :: k1) (p :: k1 -> *). p a -> G (F a :: k2)
Run Code Online (Sandbox Code Playgroud)
让我试着说:
x :: [String]
x = f (Just 'a')
Run Code Online (Sandbox Code Playgroud)
这正好和实例f
有k1 ~ Type
,a ~ Char
和p ~ Maybe
f :: forall k2. Maybe Char -> G (F Char :: k2)
Run Code Online (Sandbox Code Playgroud)
怎么办?好吧,我还需要G (F Char :: k2) ~ [String]
,但是它G
是一个非内射类型的家族,所以不知道它的论点k2
和 - F Char :: k2
应该是什么.因此,定义x
是错误的; k2
是模糊的,不可能推断它的实例化.
然而,你可以很清楚地看到,没有任何的使用f
将永远能够推断k2
.理由是k2
只出现在f
非内射型家庭应用程序下面的类型中(另一个"坏位置"是a的LHS =>
).它永远不会出现在可以推断的位置.因此,没有扩展名一样TypeApplications
,f
是无用的,没有提出这个错误不能被提及.GHC会检测到这一点,并在定义而不是用法中引发错误.您看到的错误消息与您尝试的错误相同:
f0 :: forall k10 k20 (a :: k10) (p0 :: k10 -> *). p0 a0 -> G (F a0 :: k20)
f0 = f
Run Code Online (Sandbox Code Playgroud)
这产生相同的类型不匹配,因为没有理由k20
的f0
,必须在比赛k2
中f1
.
您可以f
通过启用AllowAmbiguousTypes
来清除定义中的错误,这会禁用对所有定义的无用性检查.但是,仅此一项,这只会将错误推送到每次使用f
.为了实际调用f
,您应该启用TypeApplications
:
f0 :: forall k10 k20 (a :: k10) (p0 :: k10 -> *). p0 a0 -> G (F a0 :: k20)
f0 = f @k10 @k20 @a0 @p0
Run Code Online (Sandbox Code Playgroud)
替代方案TypeApplications
是这样的Data.Proxy.Proxy
,但除了在更高级别的背景下,这几乎已经过时了.(即便如此,一旦我们拥有类型lambda的东西,它真的会失去它的作用.)