在Haskell中的异构列表上键入安全查找

时间:2016-05-21 02:38:45

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

我想为以下数据类型开发一个类型安全查找函数:

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

明显的查找功能如下:

 lookupAttr :: (KnownSymbol s, Lookup s env ~ 'Just t) => Proxy s -> Attr env -> t
 lookupAttr s ((s',t) :* env')
       = case sameSymbol s s' of
            Just Refl -> t
            Nothing   -> lookupAttr s env'

其中Lookup类型族在单例库中定义。此定义无法在GHC 7.10.3上键入检查,并显示以下错误消息:

 Could not deduce (Lookup s xs ~ 'Just t)
   from the context (KnownSymbol s, Lookup s env ~ 'Just t)
      bound by the type signature for
             lookupAttr :: (KnownSymbol s, Lookup s env ~ 'Just t) =>
                           Proxy s -> Attr env -> t

为递归调用lookupAttr s env'生成此消息。这是合理的,因为我们有,如果

Lookup s ('(s',t') ': env) ~ 'Just t

成立,

s :~: s'

不可证明,那么

Lookup s env ~ 'Just t

必须坚持。我的问题是,我如何说服Haskell类型检查器确实这是真的?

1 个答案:

答案 0 :(得分:4)

Lookup是根据:==平等定义的,来自here。粗略地说,Lookup以这种方式实现:

type family Lookup (x :: k) (xs :: [(k, v)]) :: Maybe v where
  Lookup x '[] = Nothing
  Lookup x ('(x' , v) ': xs) = If (x :== x') (Just v) (Lookup x xs)

sameSymbol s s'上的模式匹配不会向我们提供有关Lookup s env的任何信息,也不会让GHC减少它。我们需要了解s :== s',为此我们需要使用:==的{​​{3}}。

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'

一般情况下,您不应使用KnownSymbolsameSymbolGHC.TypeLits中的任何内容,因为它们太“低级”而且不能与

当然,您可以编写自己的singletons和其他功能,而不需要使用Lookup导入;重要的是你同步术语级别和类型级别,以便术语级别模式匹配产生类型级别的相关信息。