【发布时间】:2016-07-10 08:29:57
【问题描述】:
我想创建一个数据结构来存储使用符号在类型级别标记的项目。这个:
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, singletons@2.1
【问题讨论】:
-
您可以通过添加函数
storeHead :: Store e (s ': ss) -> e s和storeTail :: Store e (s ': ss) -> Store e ss删除from'中的警告,并在匹配AtHead或InTail后在商店中使用它们。 -
您的两个
HasElemC实例重叠。 GHC 会发现不可能解除HasElemC约束,因为它在进行证明搜索时不检查先决条件。幸运的是有a well-known trick using type families andUndecidableInstances。 (事实上,这是布尔类型族少数几个好的用途之一。) -
谢谢 cchalmers,这很有效。谢谢,本杰明。在我的情况下,重叠很好:我不需要 ss 中的多态函数。虽然我将来可能需要它们。
-
@NioBium 我想你误会了我:
HasElemC无用,因为你定义实例的方式。尝试写x = HasElem "a" '["a"]; x = hasElem。它不会进行类型检查。 -
NioBium,我想@BenjaminHodgson 可能只是不喜欢重叠的实例,以至于他没有努力学习如何使用它们;学习如何不通常会更好。不幸的是,类型家庭技巧会更加挑剔。例如,类型族会拒绝使用像
a /~ (q ': a)这样的多态不等式来选择实例,因为类型族可以表示无限类型。重叠实例会很高兴这样做,因为它不会影响类型安全。
标签: haskell dependent-type singleton-type