我正在使用constraints
包(对于GHC Haskell)。我有一个类型系列,用于确定类型级别列表是否包含元素:
type family HasElem (x :: k) (xs :: [k]) where
HasElem x '[] = False
HasElem x (x ': xs) = True
HasElem x (y ': xs) = HasElem x xs
这是有效的,但它没有给我的一点是知识
HasElem x xs entails HasElem x (y ': xs)
因为类型族不是"的归纳定义是"的元素。声明(就像你在agda中一样)。我非常确定,在GADT可以升级到类型级别之前,无法用数据类型表达列表成员资格。
所以,我已经使用constraints
包写了这个:
containerEntailsLarger :: Proxy x -> Proxy xs -> Proxy b -> (HasElem x xs ~ True) :- (HasElem x (b ': xs) ~ True)
containerEntailsLarger _ _ _ = unsafeCoerceConstraint
幽灵,但它确实有效。我可以根据需要进行模式匹配以获得我需要的东西。我想知道的是它是否会导致程序崩溃。似乎它不可能,因为unsafeCoerceConstraint
被定义为:
unsafeCoerceConstraint = unsafeCoerce refl
在GHC中,类型级别在运行时被省略。我以为我会检查,只是为了确保这样做是可以的。
---编辑---
由于还没有人给出解释,我想我会稍微扩展一下这个问题。在我创造的不安全的蕴涵中,我只期待一个类型的家庭。如果我做了一些涉及类型词典的事情,那就像这样:
badEntailment :: Proxy a -> (Show a) :- (Ord a)
badEntailment _ = unsafeCoerceConstraint
我认为这几乎肯定会导致段错误。这是真的?如果是的话,是什么让它与原版不同?
---编辑2 ---
我只是想提供一些背景知道为什么我对此感兴趣。我的兴趣之一是在Haskell中对关系代数进行可用的编码。我认为无论你如何定义函数来处理类型级列表,都会有明显的事情没有被证明是正确的。例如,我之前拥有的约束(对于半连接)看起来像这样(这是来自内存,因此可能不准确):
semijoin :: ( GetOverlap as bs ~ Overlap inAs inBoth inBs
, HasElem x as, HasElem x (inAs ++ inBoth ++ inBs)) => ...
所以,对于一个人来说,如果我采用两个集合的联合,它应该包含x
中的元素as
,那我应该是显而易见的,但我不确定它可能合法地说服了这个约束求解器。所以,这是我做这个伎俩的动机。我创造了欺骗约束解算器的蕴涵,但我不知道它是否真的安全。