The problem actually reported is:
Warning: Pattern match(es) are non-exhaustive
In an equation for `fun': Patterns not matched: Inl _
Which is true. You provide a case for the Inr
constructor, but not the Inl
constructor.
What you're hoping is that since there's no way to provide a value of type Sig B
that uses the Inl
constructor (it would need an argument of type Foo B
, but the only constructor for Foo
is of type Foo A
), that ghc will notice that you don't need to handle the Inl
constructor.
The trouble is that due to bottom every type is inhabited. There are values of type Sig B
that use the Inl
constructor; there are even non-bottom values. They must contain bottom, but they are not themselves bottom. So it is possible for the program to be evaluating a call to fun
that fails to match; that's what ghc is warning about.
So to fix that you need to change fun
to something like this:
fun :: Sig B -> Int
fun (Inr Bar) = 1
fun (Inl foo) = error "whoops"
But now of course if you later add Baz :: Foo B
this function is a time bomb waiting to happen. It's be nice for ghc to warn about that, but the only way to make that happen is to pattern match foo
against a currently-exhaustive set of patterns. Unfortunately there are no valid patterns you can put there! foo
is known to be of type Foo B
, which is only inhabited by bottom, and you can't write a pattern for bottom.
But you could pass it to a function that accepts an argument of polymorphic type Foo a
. That function could then match against all the currently-existing Foo
constructors, so that you'll get a warning if you later add one. Something like this:
fun :: Sig B -> Int
fun (Inr Bar) = 1
fun (Inl foo) = errorFoo foo
where
errorFoo :: Foo a -> b
errorFoo Foo = error "whoops"
Now You've properly handled all the constructors of :+:
in fun
, the "impossible" case simply errors out if it ever actually occurs and if you ever add Baz :: Foo B
you get a warning about a non-exhaustive pattern in errorFoo
, which is at least directing you to look at fun
because it's defined in an attached where
.
On the downside, when you add unrelated constructors to Foo
(say more of type Foo A
) you'll have to add more cases to errorFoo
, and that could be unfun (though easy and mechanical) if you've got lots of functions applying this pattern.
fun (Inl Foo) = ...
is a type error. Man, you just can't catch a break! (but using_
works, of course) – Forensics