请考虑以下代码:
{-# LANGUAGE DataKinds #-} -- used to make it very clear that the param is phantom
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RoleAnnotations #-}
module Test where
data Triv = Triv
data F (f :: * -> *) (a :: Triv) = F (f (F f a))
type role F nominal phantom
我预计它会起作用,因为a
的角色对我来说似乎很明显。但是:
/.../Test.hs:7:5: error:
• Role mismatch on variable a:
Annotation says phantom but role nominal is required
• while checking a role annotation for ‘F’
Failed, modules loaded: none.
这是为什么?类型参数不是实际上是幻像(在某种意义上说,使用unsafeCoerce
将F Identity a
转换为F Identity b
可能会在运行时失败)?或者GHC的角色推理仅仅不能完成这项任务?并且,如果是后者,有没有办法说服GHC在这种情况下a
实际上是幽灵?
答案 0 :(得分:3)
这个角色实际上不是幻影。以下类型检查至少GHC 7.8.4:
{-# LANGUAGE DataKinds #-} -- used to make it very clear that the param is phantom
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE TypeFamilies #-}
module Test where
import GHC.Exts
data Triv = Triv
data F (f :: * -> *) (a :: Triv) = F (f (F f a))
type family Bad a
type instance Bad (F f 'Triv) = Int
type instance Bad (F f Any) = Bool
x = 3 :: Bad (F f 'Triv)
y = True :: Bad (F f Any)
此漏洞在8.0版本发布时(可能在之前)被插入,但there are others似乎更为基础:
{-# LANGUAGE DataKinds #-} -- used to make it very clear that the param is phantom
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE TypeFamilies #-}
module Test where
data Triv = Triv
data F (f :: * -> *) (a :: Triv) = F (f (F f a))
type family Succ :: Triv -> Triv
type family Bad a where
Bad (F f 'Triv) = Int
Bad (F f a) = Bool
x = 3 :: Bad (F f 'Triv)
y = True :: Bad (F f (Succ 'Triv))
如果你反对我不能写F Bad
,那么它很容易解决;您可以将以下附录添加到前两个文件中的任何一个。
data BadData a = BadData (Bad a)
xF :: F BadData 'Triv
xF = F (BadData x)
yF :: F BadData (Succ 'Triv)
yF = F (BadData y)
答案 1 :(得分:1)
f
的参数可能具有名义角色。我需要Triv
种至少有两个居民来展示反例。
data Triv = T1 | T2
data family K a :: *
data instance K (F K T1) = K1 Int Int
data instance K (F K T2) = K2 Double
coerce :: F K T1 -> F K T2
-- i.e., K (F K T1) -> K (F K T2)
-- That should not typecheck.