我想创建一个数据结构来存储使用Symbol标记在类型级别的项目。这样:
data Store e (ss :: [Symbol]) where
Nil :: Store e '[]
Cons :: e s -> Store e ss -> Store e (s ': ss)
data HasElem (a :: k) (as :: [k]) where
AtHead :: HasElem a (a ': as)
InTail :: HasElem a as -> HasElem a (b ': as)
class HasElemC (a :: k) (as :: [k]) where hasElem :: HasElem a as
instance HasElemC {OVERLAPPING} a (a ': as) where hasElem = AtHead
instance HasElemC a as => HasElemC a (b ': as) where hasElem = InTail hasElem
from :: HasElemC s ss => Store e ss -> e s
from = from' hasElem
from' :: HasElem s ss -> Store e ss -> e s
-- from' _ Nil = undefined
from' h (Cons element store) = case h of
AtHead -> element
InTail h' -> from' h' store
有点工作,如果你忽略了编译器警告我不提供from' _ Nil
定义这一事实(顺便说一句,为什么呢?有没有办法让它停止?)但是我真的想做什么一开始是以惯用的方式使用单例库,而不是编写我自己的类型级代码。像这样:
import Data.Singletons.Prelude.List
data Store e (ss :: [Symbol]) where
Nil :: Store e '[]
Cons :: Sing s -> e s -> Store e ss -> Store e (s ': ss)
from :: Elem s ss ~ True => Store e ss -> e s
from (Cons evidence element nested) = ???
可悲的是,我无法弄清楚如何将上下文转换为命题平等。你如何使用单身人士图书馆的积木去做我想做的事情?
ghc@7.10.3,singleletons@2.1
答案 0 :(得分:8)
Don't use Booleans!在这一点上,我似乎keep repeating myself:布尔人在依赖类型编程中的用处非常有限,越早开始学习这种习惯就越好。
Elem s ss ~ True
上下文向您承诺s
位于某个地方ss
,但它不会说其中。当您需要从s
列表中生成ss
- 值时,这会让您陷入困境。一点不足以满足您的目的。
将此与原始HasElem
类型的计算有用性进行比较,该类型的结构类似于给出列表中元素索引的自然数。 (将There (There Here)
之类的值的形状与S (S Z)
的形状进行比较。)要从s
列表中生成ss
,您只需要取消引用索引。
也就是说,您仍然可以恢复您丢弃的信息,并从HasElem x xs
的上下文中提取Elem x xs ~ True
值。但是,这很乏味 - 您必须在列表中搜索该项目(您已经做过以评估Elem x xs
!)并消除不可能的情况。在Agda工作(省略定义):
recover : {A : Set}
(_=?_ : (x : A) -> (y : A) -> Dec (x == y))
(x : A) (xs : List A) ->
(elem {{_=?_}} x xs == true) ->
Elem x xs
recover _=?_ x [] ()
recover _=?_ x (y :: ys) prf with x =? y
recover _=?_ x (.x :: ys) prf | yes refl = here
recover _=?_ x (y :: ys) prf | no p = there (recover _=?_ x ys prf)
但是,所有这些工作都是不必要的。只需使用信息丰富的证明术语即可。
顺便说一句,您应该能够通过在左侧进行Elem
匹配而不是在case
- 表达式中停止GHC警告您不完整的模式:
from' :: HasElem s ss -> Store e ss -> e s
from' AtHead (Cons element store) = element
from' (InTail i) (Cons element store) = from' i store
当你进入定义的右侧时,模式匹配为时已晚,无法改进左侧其他术语的可能构造函数。