Как мне показать, что что-либо следует из значения типа без конструкторов в Scala?Я хотел бы сделать сопоставление с шаблоном для значения и сделать так, чтобы Scala сообщала мне, что ни один шаблон не может соответствовать, но я открыт для других предложений.Вот краткий пример того, почему это было бы полезно.
Проверка отрицательных значений
В Scala можно определять натуральные числа на уровне типа, например, с кодировкой Peano.
sealed trait Nat
sealed trait Zero extends Nat
sealed trait Succ[N <: Nat] extends Nat
Из этого мы можем определить, что значит число быть четным.Ноль является четным, и любое число два больше, чем четное число также является четным.
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]]]
Из этого мы можем показать, что, например, два является четным:
val `two is even`: Even[Succ[Succ[Zero]]] = Step(Base())
Но я не могучтобы показать, что это не так, даже если компилятор может сказать мне, что ни Base
, ни Step
не могут обитать в типе.
def `one is odd`(impossible: Even[Succ[Zero]]): Nothing = impossible match {
case _: Base => ???
case _: Step[_] => ???
}
Компилятор с радостью скажет мне, что ни один из случаев, которые яВозможно, с ошибкой pattern type is incompatible with expected type
, но если оставить блок match
пустым, это будет ошибка компиляции.
Есть ли способ доказать это конструктивно?Если пустое совпадение с образцом - путь, я бы принял любую версию Scala или даже макрос или плагин, если я все еще получаю ошибки для пустых совпадений с образцом, когда тип обитаем.Может быть, я лаю не на том дереве, соответствует ли шаблон неправильной идее - может ли EFQ показываться другим способом?
Примечание. Доказательство того, что один нечетен, можно сделать с помощью другого (но эквивалентного) определенияровность - но это не главное.Более короткий пример того, почему может понадобиться EFQ:
sealed trait Bottom
def `bottom implies anything`(btm: Bottom): Any = ???