有关Haskell中异构列表的类型安全查找的更多信息

时间:2016-06-19 23:28:41

标签: haskell dependent-type type-level-computation

我试图在Haskell中使用依赖类型编程获得一些乐趣,更具体地说是使用类型安全查找操作。 Previously,我已经询问了如何为以下数据类型实现查找操作:

data Attr (xs :: [(Symbol,*)]) where
   Nil  :: Attr '[]
   (:*) :: (Sing s, t) -> Attr xs -> Attr ('(s , t) ': xs)

我得到了答案:

lookupAttr :: (Lookup s env ~ 'Just t) => Sing s -> Attr env -> t
lookupAttr s ((s', t) :* env') = case s %:== s' of
   STrue  -> t
   SFalse -> lookupAttr s env'

工作正常。现在,我想定义一个类型语法值的异构列表,由类型Exp表示:

{-# LANGUAGE GADTs, TypeFamilies, DataKinds, TypeOperators, PolyKinds #-}
import Data.Singletons.Prelude.List
import Data.Singletons.Prelude.Bool
import Data.Singletons.Prelude.Eq

data Exp (env :: [(Symbol,*)]) :: * -> * where
   Value :: String -> Exp env String
   Var :: (Lookup s env ~ 'Just t) => Sing s -> Exp env t
   Op :: Exp env t -> Exp env t -> Exp env t

异构列表类型由Env数据类型定义:

data Env (env :: [(Symbol,*)]) where
  Nil  :: Env '[]
  Cons :: (Lookup s' env ~ 'Nothing) =>
         (Sing s' ,
          Exp ('(s', a) ': env) a) ->
         Env env ->
         Env ('( s',a) ': env)

使用这些数据类型,我使用某种存在量化(类型Ex2)定义查找函数:

data Ex2 (p :: k -> k' -> *) where
   Ex2 :: p e i -> Ex2 p

lookupEnv :: Lookup s env ~ 'Just t => Sing s -> Env env -> Ex2 Exp
lookupEnv s (Cons (s',e) env)
    = case s %:== s' of
         STrue -> Ex2 e
         SFalse -> lookupEnv s env

到目前为止,这么好。现在,我遇到了一些有趣的问题:

1)有没有办法定义lookupEnv而不使用Ex2类型提供的这种存在量化?

2)假设我想定义一个操作来修改类型为Env的值的给定条目。明确尝试定义此函数是

modifyEnv :: Lookup s env ~ 'Just t => Sing s -> Exp env t -> Env env -> Env env
modifyEnv s e (Cons (s',e') env')
     = case s %:== s' of
          STrue -> Cons (s', Op e e') env'
          SFalse -> Cons (s',e') (modifyEnv s e env')

函数modifyEnv在环境中与另一个表达式组合。 GHC不接受此功能,返回隐藏的错误消息。我怎么能定义这样的修改函数?

1 个答案:

答案 0 :(得分:2)

我意识到这不是一个完整的解决方案,因为它没有使用Symbol - 索引Env讽刺,但它可能会给你一个很好的起点。我正在使用“类型de Bruijn索引到上下文”类型:

{-# LANGUAGE GADTs, TypeFamilies, DataKinds, TypeOperators #-}

data Var (ctx :: [*]) :: * -> * where
    Here :: Var (a ': ctx) a
    There :: Var ctx a -> Var (b ': ctx) a

data Exp (ctx :: [*]) :: * -> * where
    Value :: String -> Exp ctx String
    Var :: Var ctx t -> Exp ctx t
    Op :: Exp ctx t -> Exp ctx t -> Exp ctx t

data Env (ctx :: [*]) where
    Nil :: Env '[]
    Cons :: Exp (a ': ctx) a -> Env ctx -> Env (a ': ctx)

这允许编写lookupEnv的打字版本,如下所示:

lookupEnv :: Env ctx -> Var ctx t -> Exp ctx t
lookupEnv (Cons e env) v = case v of
    Here -> e
    There v -> weaken $ lookupEnv env v

通过编写以下弱化函数:

weaken :: Exp ctx t -> Exp (a ': ctx) t
weaken (Value s) = Value s
weaken (Var v) = Var (There v)
weaken (Op f e) = Op (weaken f) (weaken e)

在我看来,使用Symbol - 索引的上下文,这是最后一个weaken步骤失败,因为Lookup s ctx ~ Nothing似乎没有足够的GHC结构证明你需要weaken(你可以改变上下文,因为你知道不会出现阴影问题)。

相关问题