Haskell GADT可以用来证明GHC中的类型不等式吗?
因此,在我不断尝试通过哈斯克尔的小练习来半了解库里·霍华德的过程中,我被困在了这一点上:Haskell GADT可以用来证明GHC中的类型不等式吗?,haskell,curry-howard,Haskell,Curry Howard,因此,在我不断尝试通过哈斯克尔的小练习来半了解库里·霍华德的过程中,我被困在了这一点上: {-# LANGUAGE GADTs #-} import Data.Void type Not a = a -> Void -- | The type of type equality proofs, which can only be instantiated if a = b. data Equal a b where Refl :: Equal a a -- | Derive
{-# LANGUAGE GADTs #-}
import Data.Void
type Not a = a -> Void
-- | The type of type equality proofs, which can only be instantiated if a = b.
data Equal a b where
Refl :: Equal a a
-- | Derive a contradiction from a putative proof of @Equal Int Char@.
intIsNotChar :: Not (Equal Int Char)
intIsNotChar intIsChar = ???
显然,类型Equal Int Char
没有(非底部)居民,因此语义上应该有一个absurdEquality::Equal Int Char->a
函数。。。但就我的一生而言,除了使用undefined
,我想不出任何方法来编写一个
因此,要么:
我怀疑答案是这样的:编译器无法利用没有a=b的
Equal
构造函数这一事实。但是如果是这样的话,是什么让它成为现实呢?我不理解使用未定义的的问题,每种类型都有Haskell中的bottom。我们的语言没有很强的规范化。。。你找错东西了Equal Int Char
导致类型错误异常保存不好。看
{-# LANGUAGE GADTs, TypeFamilies #-}
data Equal a b where
Refl :: Equal a a
type family Pick cond a b
type instance Pick Char a b = a
type instance Pick Int a b = b
newtype Picker cond a b = Picker (Pick cond a b)
pick :: b -> Picker Int a b
pick = Picker
unpick :: Picker Char a b -> a
unpick (Picker x) = x
samePicker :: Equal t1 t2 -> Picker t1 a b -> Picker t2 a b
samePicker Refl x = x
absurdCoerce :: Equal Int Char -> a -> b
absurdCoerce e x = unpick (samePicker e (pick x))
您可以使用它来创建所需的函数
absurdEquality e = absurdCoerce e ()
但这将产生未定义的行为作为其计算规则false
应导致程序中止,或至少永远运行。中止是一种计算规则,类似于通过添加not将最小逻辑转化为初始逻辑。正确的定义是
absurdEquality e = error "you have a type error likely to cause big problems"
至于标题中的问题:基本上不是。据我所知,类型不等式在当前的Haskell中是不可实际表示的。类型系统即将发生的变化可能会导致这种情况变得更好,但到目前为止,我们有平等,但没有不平等 这是Philip JF解决方案的一个简短版本,这是依赖型理论家多年来驳斥方程的方式
type family Discriminate x
type instance Discriminate Int = ()
type instance Discriminate Char = Void
transport :: Equal a b -> Discriminate a -> Discriminate b
transport Refl d = d
refute :: Equal Int Char -> Void
refute q = transport q ()
为了证明事物是不同的,您必须通过提供一个计算上下文来捕捉它们的不同行为,从而产生不同的观察结果discrime
正好提供了这样一个上下文:一个类型级程序,它以不同的方式处理这两种类型
没有必要求助于未定义来解决此问题。总编程有时包括拒绝不可能的输入。即使在未定义的
可用的情况下,我也建议不要在total方法足够的情况下使用它:total方法解释了为什么有些事情不可能,typechecker会确认<代码>未定义
仅记录您的承诺。事实上,这种反驳方法是警句在确保案例分析涵盖其领域的同时,如何省去“不可能的案例”
至于计算行为,请注意,反驳
,通过传输
在q
中必须严格,并且q
不能在空上下文中计算到head范式,这仅仅是因为不存在这样的head范式(当然也因为计算保留了类型)。在total设置中,我们可以确保在运行时永远不会调用returne
。在Haskell中,我们至少可以肯定,在我们必须对其作出回应之前,它的论点会出现分歧或抛出异常。懒惰的版本,如
absurdEquality e = error "you have a type error likely to cause big problems"
将忽略e
的毒性,并告诉您有类型错误,而您没有。我更喜欢
absurdEquality e = e `seq` error "sue me if this happens"
如果诚实的反驳太像艰苦的工作。请看:@dbaupp:不是重复的——这个问题并不是为了证明不平等。@C.a.McCann,啊,是的,我想在我开始胡乱指责之前,我应该仔细阅读。:)请注意,seq e(错误“如果发生这种情况请告我”)
可以在第一个参数之前计算第二个参数,如果这是一个问题,您可以使用pseq
()。