如果我有一个由有限DataKind
{-# LANGUAGE DataKinds #-}
data K = A | B
data Ty (a :: K) = Ty { ... }
和一种存在类型,它会忘记类型中K
的确切选择...但会在传递的字典中记住它。
class AK (t :: K) where k :: Ty t -> K
instance AK A where k _ = A
instance AK B where k _ = B
data ATy where ATy :: AK a => Ty a -> ATy
ATy <-> Either (Ty A) (Ty B)
确实如此,但如果我想写一个我需要使用的证人unsafeCoerce
getATy :: ATy -> Either (Ty A) (Ty B)
getATy (ATy it) = case k it of
A -> Left (unsafeCoerce it)
B -> Right (unsafeCoerce it)
所以一般来说这是有用的 - 我可以忘记使用K
选择ATy
并使用getATy
部分记住它。总而言之,这充分利用了我所拥有的类型信息。
但是,如果正确完成,这种类型的信息感觉应该是“显而易见的”。
有没有办法在不使用unsafeCoerce
的情况下实现上述目标?有没有办法摆脱存在主义中的AK
约束?这种技术是否可以完全基于数据类型提供的信息约束来执行?
答案 0 :(得分:9)
如果要对存在类型进行运行时案例分析,还需要单例表示:
{-# LANGUAGE DataKinds, GADTs, KindSignatures, ScopedTypeVariables #-}
data K = A | B
-- runtime version of K.
data SK (k :: K) where
SA :: SK A
SB :: SK B
-- ScopedTypeVariables makes it easy to specify which "k" we want.
class AK (k :: K) where
k :: SK k
instance AK A where k = SA
instance AK B where k = SB
data Ty (a :: K) = Ty
data ATy where
ATy :: AK k => Ty k -> ATy
getATy :: ATy -> Either (Ty A) (Ty B)
getATy (ATy (ty :: Ty k)) = case (k :: SK k) of
SA -> Left ty
SB -> Right ty
此处可以使用singletons
包来取消样板:
{-# LANGUAGE DataKinds, GADTs, TypeFamilies, TemplateHaskell, ScopedTypeVariables #-}
import Data.Singletons.TH
$(singletons [d| data K = A | B |])
data Ty (a :: K) = Ty
data ATy where
ATy :: SingI k => Ty k -> ATy
getATy :: ATy -> Either (Ty A) (Ty B)
getATy (ATy (ty :: Ty k)) = case (sing :: Sing k) of
SA -> Left ty
SB -> Right ty
关于你的上一个问题:
有没有办法摆脱存在主义中的AK约束? 这种技术可以完全基于信息来执行 数据种类提供的约束?
只要我们只将数据类型作为类型参数,信息就不存在运行时,我们就无法对其进行任何分析。例如,采用以下类型:
data ATy where
ATy :: Ty k -> ATy
我们永远无法在k
中实例化Ty k
;它必须保持多态。
有多种方法可以提供运行时类型信息;隐含地通过词典是一种选择,正如我们所见:
data ATy where
ATy :: AK k => Ty k -> ATy
此处AK k
只是指向SK
的指针(因为AK
类只有一个方法,我们没有该类的字典,只是一个指向方法的普通指针),构造函数中的一个额外字段。我们也可以选择明确该字段:
data ATy where
ATy :: SK k -> Ty k -> ATy
和运行时表示几乎相同。
第三种选择是使用GADT构造函数对类型进行编码:
data ATy where
ATyA :: Ty A -> ATy
ATyB :: Ty B -> ATy
这个解决方案性能非常好,因为没有空间开销,因为构造函数已经对类型进行了编码。它类似于具有隐藏类型参数的Either
。