haskell – GADT的彻底检查失败

请考虑以下代码:

data (:+:) f g a = Inl (f a) | Inr (g a)

data A
data B

data Foo l where
  Foo :: Foo A

data Bar l where
  Bar :: Bar B

type Sig = Foo :+: Bar

fun :: Sig B -> Int
fun (Inr Bar) = 1

尽管乐趣是一场穷尽的比赛,但是在编译的时候,GHC抱怨失踪的情况.但是,如果我添加另一个构造函数:

data (:+:) f g a = Inl (f a) | Inr (g a)

data A
data B

data Foo l where
  Foo :: Foo A
  Baz :: Foo B

data Bar l where
  Bar :: Bar B

type Sig = Foo :+: Bar

fun :: Sig B -> Int
fun (Inr Bar) = 1
fun (Inl Baz) = 2

然后,GHC正确地检测到乐趣是完全的.

我正在使用与我工作相似的代码,如果我错过了案例,GHC会提醒警告,如果我没有提出警告,则不要提出警告.为什么GHC对第一个程序抱怨,如何在没有添加伪造构造函数或案例的情况下,先获取第一个样本来编译而不发出警告?

实际报道的问题是:

Warning: Pattern match(es) are non-exhaustive
         In an equation for `fun': Patterns not matched: Inl _

哪个是真的您为Inr构造函数提供了一个案例,但不提供Inl构造函数.

你希望的是,由于没有办法提供使用Inl构造函数的类型Sig B的值(它需要一个类型为Foo B的参数,但是Foo的唯一构造函数是Foo A类型),那ghc将注意到您不需要处理Inl构造函数.

麻烦的是,由于底部每种类型都是有人居住的.有类型Sig B的值使用Inl构造函数;甚至还有非底线值.它们必须包含底部,但它们本身不是底部的.所以程序有可能正在评估一个没有匹配的乐趣的呼唤;这是ghc警告的.

所以要修复,你需要改变乐趣,像这样:

fun :: Sig B -> Int
fun (Inr Bar) = 1
fun (Inl foo) = error "whoops"

但现在当然如果你以后再加Baz :: Foo B这个功能就是定时炸弹等待发生.对于ghc来说,这是很好的警告,但是,发生这种情况的唯一方法是将模式匹配foo与当前穷尽的模式集合.不幸的是没有有效的模式,你可以放在那里! foo被称为Foo B型,它只是由底部居住,你不能写一个底部的图案.

但是您可以将其传递给接受多态类型Foo a的参数的函数.那个功能可以与所有当前存在的Foo构造函数相匹配,以便如果你以后添加一个,你会收到一个警告.这样的事情

fun :: Sig B -> Int
fun (Inr Bar) = 1
fun (Inl foo) = errorFoo foo
    where 
        errorFoo :: Foo a -> b
        errorFoo Foo = error "whoops"

现在你已经正确地处理了所有的构造函数:在有趣的情况下,“不可能”的情况只是错误的,如果它实际上发生,如果你添加Baz :: Foo B,你会发现一个非穷尽的模式在errorFoo ,这至少指示你看看乐趣,因为它被定义在附加的地方.

在缺点上,当您向Foo添加无关的构造函数(更多类型为Foo A)时,您将不得不向errorFoo添加更多的案例,如果您有很多应用程序这种模式.

http://stackoverflow.com/questions/16225281/gadts-failed-exhaustiveness-checking

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:haskell – GADT的彻底检查失败