我在Haskell中尝试使用和,并开始查看GHC生成的核心代码。
这里有一个小的测试用例来激发我的问题:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
module TestCase where
data Ty = TyBool | TyInt
type family InterpTy (t :: Ty) :: *
type instance InterpTy TyBool = Bool
type instance InterpTy TyInt = Int
data Expr (a :: Ty) where
I :: Int -> Expr TyInt
B :: Bool -> Expr TyBool
eval :: Expr a -> InterpTy a
eval (I i) = i
eval (B b) = b
让我们来看一下
eval
函数生成的核心内容。TestCase.eval =
\ (@ (a_aKM :: TestCase.Ty)) (ds_dL3 :: TestCase.Expr a_aKM) ->
case ds_dL3 of _ [Occ=Dead] {
TestCase.I dt_dLh i_as6 ->
i_as6
`cast` (Sub (Sym TestCase.TFCo:R:InterpTyTyInt[0])
; (TestCase.InterpTy (Sym dt_dLh))_R
:: GHC.Types.Int ~# TestCase.InterpTy a_aKM);
TestCase.B dt_dLc b_as7 ->
b_as7
`cast` (Sub (Sym TestCase.TFCo:R:InterpTyTyBool[0])
; (TestCase.InterpTy (Sym dt_dLc))_R
:: GHC.Types.Bool ~# TestCase.InterpTy a_aKM)
}
显然,我们需要携带有关特定分支中 a
可能的信息。如果我不对 Datakind 进行索引并且不使用 TypeFamilies,则转换会更容易理解。
大概是这样:
Main.eval =
\ (@ a_a1hg) (ds_d1sQ :: Main.Simpl a_a1hg) ->
case ds_d1sQ of _ [Occ=Dead] {
Main.I' dt_d1to i_aFa ->
i_aFa
`cast` (Sub (Sym dt_d1to) :: GHC.Integer.Type.Integer ~# a_a1hg);
Main.B' dt_d1tk b_aFb ->
b_aFb `cast` (Sub (Sym dt_d1tk) :: GHC.Types.Bool ~# a_a1hg)
}
我完全理解这个,但是示例中让我困扰的是这一部分:
(Sub (Sym TestCase.TFCo:R:InterpTyTyInt[0])
; (TestCase.InterpTy (Sym dt_dLh))_R
:: GHC.Types.Int ~# TestCase.InterpTy a_aKM);
第二行真的让我感到困惑。分号在这里做什么?它似乎有点不合适,还是我漏掉了什么?是否有一个地方可以阅读相关资料(如果您能推荐一篇论文,我会非常感激)。
此致敬礼,
raichoo