假设我正在编写DSL并希望支持幻像类型支持和严重类型化的表达式。我的值类型可能是
{-# LANGUAGE GADTs, DataKinds #-}
data Ty = Num | Bool deriving (Typeable)
data Val a where
VNum :: Int -> Val Num
VBool :: Bool -> Val Bool
我可以使用幻像删除版
{-# LANGUAGE ExistentialQuantification #-}
data Valunk = forall a . Valunk (V' a)
现在,我可以通过Valunk
case
和VNum
VBool
操作getNum :: Valunk -> Maybe (Val Num)
getNum (Valunk n@(VNum _)) = Just n
getNum _ = Nothing
的值,甚至以这种方式重新构建我的幻像类型
Typeable
但这只是感觉我正在重新实现Typeable
机制。不幸的是,GHC不允许我为Val
src/Types/Core.hs:97:13:
Can't make a derived instance of `Typeable (Val a)':
Val must only have arguments of kind `*'
In the data declaration for Val
getIt :: Typeable a => Valunk -> Maybe (Val a)
getIt (Valunk v) = cast v
有没有办法解决这个限制?我很想写
class Typeably b x where kast :: x a -> Maybe (x b)
instance Typeably Num Val where
kast n@(VNum _) = Just n
kast _ = Nothing
但是现在我不得不诉诸这样的机器
{{1}}
我的所有类型。
答案 0 :(得分:1)
您可以自己派生Data.Typeable:
{-# LANGUAGE GADTs, DataKinds, DeriveDataTypeable, ExistentialQuantification #-}
import Data.Typeable
data Ty = TNum | TBool deriving Typeable
data Valunk = forall a. Typeable a => Valunk a
data Val a where
VInt :: Int -> Val TNum
VBool :: Bool -> Val TBool
instance Show (Val a) where
show (VInt a) = show a
show (VBool a) = show a
valtypenam = mkTyCon3 "package" "module" "Val"
instance Typeable (Val a) where
typeOf _ = mkTyConApp valtypenam []
getIt :: Valunk -> Maybe (Val a)
getIt (Valunk p) = cast p
这将提供get it功能。只需确保正确命名您的类型(因此如实提交文件包,模块和类型)否则其他包可能会遇到问题。
有关如何编写这些实例的更多示例,请查看:Data.Derive.Typeable source。
编辑:我在代码中有一个非常奇怪的副本和过去的错误,但现在它有效。
答案 1 :(得分:1)
首先,您需要存储Valunk
中量化类型位于Typeable
的见证人:
data Valunk = forall a . Typeable a => Valunk (Val a)
一旦你有了这个,你可以使用gcast
来实现你的要求:
getIt :: Typeable a => Valunk -> Maybe (Val a)
getIt (Valunk v) = gcast v
用以下方法测试:
data Val a where
VNum :: Int -> Val Int
VBool :: Bool -> Val Bool