How do I show that anything follows from a value of a type with no constructors in Scala? I would like to do a pattern match on the value and have Scala tell me that no patterns can match, but I am open for other suggestions. Here is a short example of why it would be useful.
Proving negatives
In Scala it is possible to define the natural numbers on a type level, e.g. with Peano encoding.
sealed trait Nat
sealed trait Zero extends Nat
sealed trait Succ[N <: Nat] extends Nat
From this we can define what it means for a number to be even. Zero is even, and any number two more than an even number is also even.
sealed trait Even[N <: Nat]
sealed case class Base() extends Even[Zero]
sealed case class Step[N <: Nat](evenN: Even[N]) extends Even[Succ[Succ[N]]]
From this we can show that e.g. two is even:
val `two is even`: Even[Succ[Succ[Zero]]] = Step(Base())
But I am unable to show that one is not even, even though the compiler can tell me that neither Base nor Step can inhabit the type.
def `one is odd`(impossible: Even[Succ[Zero]]): Nothing = impossible match {
case _: Base => ???
case _: Step[_] => ???
}
The compiler will happily tell me that none of the cases I've given are possible with the error pattern type is incompatible with expected type, but leaving the match block empty will be a compile error.
Is there any way to prove this constructively? If empty pattern matches is the way to go - I'd accept any version of Scala or even a macro or plugin, as long as I still get errors for empty pattern matches when the type is inhabited. Maybe I am barking up the wrong tree, is a pattern match the wrong idea - could EFQ be shown in some other way?
Note: Proving that one is odd could be done with another (but equivalent) definition of evenness - but that is not the point. A shorter example of why EFQ could be needed:
sealed trait Bottom
def `bottom implies anything`(btm: Bottom): Any = ???
It may be impossible to prove
ex falsofor an arbitrary uninhabited type in Scala, but it's still possible to prove thatEven[Succ[Zero]] => Nothing. My proof requires only a small modification to yourNatdefinition to work around a missing feature in Scala. Here it is: