你要求的东西是不可能的,但很像它可能会做的事情。这是不可能的,因为证明需要对类型级别的布尔值进行案例分析,但是您没有数据可以让您发生此类事件。解决方法是通过单例仅包含此类信息。
首先,让我注意你的 for 类型idemp
有点模糊。约束a ~ b
只是将同一事物命名两次。以下类型检查:
idemq :: p (Or b b) -> p b
idemq = undefined
idemp :: a ~ b => p (Or a b) -> p a
idemp = idemq
(如果您有一个不包含的约束a ~ t
,通常最好替换为。例外情况是在声明中:实例中的头部将匹配任何内容,因此即使该内容尚未明显变为 ,该实例也会触发。但我离题。)t
a
t
a
instance
a
t
我声称idemq
无法定义,因为我们没有关于b
. 唯一可用的数据存在p
于某物中,我们不知道是什么p
。
我们需要根据案例进行推理b
。请记住,对于一般递归类型族,我们可以定义类型级别的布尔值,它们既不是True
也不是False
。如果我打开UndecidableInstances
,我可以定义
type family Loop (b :: Bool) :: Bool
type instance Loop True = Loop False
type instance Loop False = Loop True
所以Loop True
不能简化为True
or False
,而且在局部更糟的是,没有办法证明
Or (Loop True) (Loop True) ~ Loop True -- this ain't so
没有办法摆脱它。我们需要运行时证据来证明我们b
是表现良好的布尔值之一,它以某种方式计算出一个值。让我们歌唱
data Booly :: Bool -> * where
Truey :: Booly True
Falsey :: Booly False
如果我们知道Booly b
,我们可以做一个案例分析,它会告诉我们是什么b
。然后每个案例都会顺利通过。这就是我的玩法,使用定义的相等类型PolyKinds
来打包事实,而不是抽象使用 uses p b
。
data (:=:) a b where
Refl :: a :=: a
我们的关键事实现在被清楚地陈述和证明:
orIdem :: Booly b -> Or b b :=: b
orIdem Truey = Refl
orIdem Falsey = Refl
我们可以通过严格的案例分析来部署这个事实:
idemp :: Booly b -> p (Or b b) -> p b
idemp b p = case orIdem b of Refl -> p
案例分析必须严格,以检查证据不是一些循环的谎言,而是一个诚实的善良Refl
默默地打包只是Or b b ~ b
修复类型所需的证据。
如果您不想明确地使用所有这些单例值,您可以按照 kosmikus 的建议,将它们隐藏在字典中,并在需要时提取它们。
Richard Eisenberg 和 Stephanie Weirich 有一个 Template Haskell 库,可以为您处理这些家庭和类。她也可以构建它们并让您编写
orIdem pi b :: Bool. Or b b :=: b
orIdem {True} = Refl
orIdem {False} = Refl
其中pi b :: Bool.
扩展为forall b :: Bool. Booly b ->
。
但它是如此的闲聊。这就是为什么我的团队正在努力pi
向 Haskell 添加一个实际的量词,它是一个非参数量词(与forall
和不同->
),它可以由 Haskell 类型语言和术语语言之间的非平凡交集中的东西实例化。这pi
也可能有一个“隐式”变体,其中参数默认保持隐藏。两者分别对应使用单例族和类,但不需要定义数据类型三遍来获得额外的工具包。
It might be worth mentioning that in a total type theory, it is not needed to pass the extra copy of the Boolean b
at run time. The thing is, b
is used only to make the proof that data may be transported from p (Or b b)
to p b
, not necessarily to make the data being transported. We don't compute under binders at run time, so there's no way to cook up a dishonest proof of the equation, hence we can erase the proof component and the copy of b
that delivers it. As Randy Pollack says, the best thing about working in a strongly normalizing calculus is not having to normalize things.