К сожалению, это не то, что вы могли бы легко проверить во время компиляции. Ну, по крайней мере, нет, если вы не ограничиваете операции над своим типом. Если ваша цель - просто проверить, что числовой литерал отличен от нуля, вы можете легко написать макрос, который проверяет это свойство. Однако я не вижу никакой пользы в доказательстве того, что отрицательный литерал действительно отрицательный.
Проблема не является ограничением Scala - которая имеет очень сильную систему типов, но тот факт, что (в достаточно сложной программе) вы не можете статически знать все возможные состояния. Однако вы можете попытаться переопределить набор всех возможных состояний.
Рассмотрим пример введения типа NegativeNumber
, который только когда-либо представляет отрицательное число. Для простоты мы определяем только одну операцию: plus
.
Предположим, вы допустили бы только добавление нескольких NegativeNumber
, тогда система типов может быть использована для гарантии того, что каждый NegativeNumber
действительно является отрицательным числом. Но это кажется действительно ограничительным, поэтому полезный пример, безусловно, позволит нам добавить, по крайней мере, NegativeNumber
и общий Int
.
Что делать, если у вас было выражение val z: NegativeNumber = plus(x, y)
, где вы не знаете значения x
и y
статически (возможно, они возвращаются функцией). Как вы знаете (статически), что z
is indead отрицательное число?
подход к решению этой проблемы было бы ввести Abstract Interpretation, который должен быть запущен на представлении вашей программы (Source Code, Abstract Syntax Tree, ...).
Например, вы могли бы определить Решетку на номера со следующими элементами:
Top
: все номера
+
: все положительные числа
0
: число 0
-
: все отрицательные числа
Bottom
: не число - только ввел, что каждая пара элементов имеет наибольшую нижнюю границу
с упорядочением Top
> (+
, 0
, -
)>Bottom
.
Затем вам нужно определить семантику для операций. Принимая коммутативную метод plus
из нашего примера:
plus(Bottom, something)
всегда Bottom
, так как вы не можете вычислить что-то с помощью недопустимых номеров
plus(Top, x)
, x != Bottom
всегда Top
, потому что добавление произвольного числа на любое число всегда произвольное номер
plus(+, +)
является +
, потому что добавление двух положительных чисел всегда будет давать положительное число
plus(-, -)
является -
, так как добавление двух отрицательных чисел всегда будет давать отрицательное число
plus(0, x)
, x != Bottom
- x
, потому что 0
является личностью добавления.
Проблема заключается в том, что
plus - +
будет Top
, потому что вы не знаете, если это положительное или отрицательное число.
Так быть статически безопасным, вы должны принять консервативный подход и запретить такую операцию.
Есть more sophisticated numerical domains, но в конечном итоге все они страдают от одной и той же проблемы: они представляют собой чрезмерное приближение к фактическому состоянию программы.
Я бы сказал, что проблема похожа на целочисленное переполнение/недополнение: Как правило, вы не знаете, статически ли операция демонстрирует переполнение - вы это знаете только во время выполнения.