Проверка на сюръективность при закрытии типа возврата - PullRequest
6 голосов
/ 15 мая 2019

Scala может предупреждать, когда сопоставление с образцом для запечатанного типа не является исчерпывающим, однако можем ли мы проверить, что функция возвращает все случаи, когда возвращаемый тип запечатан? Например, рассмотрим следующий ADT

sealed trait Foo
case object Bar extends Foo
case object Qux extends Foo

Тогда функция f: Foo => String для алгебраического типа данных Foo

def f(x: Foo): String = x match {
  case Bar => "bar"
}

поднимает предупреждение

match may not be exhaustive.
It would fail on the following input: Qux
def f(x: Foo) = x match {

Можно ли вызвать подобное предупреждение о неисчерпании, если тип возвращаемого значения - ADT, например, в следующей реализации f: String => Foo:

def f(x: String): Foo = x match {
  case "bar" => Bar
  // warn because we never return Qux 
}

Ответы [ 2 ]

5 голосов
/ 15 мая 2019

Возможно, это не совсем ответ, но в любом случае это слишком длинный комментарий.

Сопоставление с образцом и возвращаемые значения функции - это две разные вещи.Бывший работает на уровне тип , последний на уровне значение .Когда вы сопоставляете шаблон с Bar, вы сопоставляете шаблон с типом (как, например, Int).Но когда вы возвращаете Bar, вы возвращаете значение объекта case (как, например, 42).

Сюръективная функция определяется как:

Для каждого члена y домена, существует по крайней мере один член x домена, такой что f (x) = y .

Теперь легко понять, почему эта проверка невозможна / невозможна.Что если ваш Bar был не объектом case, а классом?Например,

final case class Bar(name: String, surname: String, age: Int)

Вы должны ожидать, что будет использоваться каждое возможное значение Bar (например, имя = "Джон", фамилия = "Смит", возраст = 42).

Конечно, это не то, что вы хотели;Вы описали сценарий, в котором каждый подтип имеет ровно одного обитателя, потому что Bar и Qux в основном являются перечислениями, и я понимаю, почему такая проверка может иметь смысл для вас.Но это должно быть реализовано для общего случая произвольного числа жителей на (под) тип - необходимо убедиться, что кодомен содержит хотя бы одно значение типа Bar, хотя бы одно значение типа Qux и т. Д.... что не очень полезно.

Как я уже сказал, это не совсем ответ, но я хотел дать вам представление о том, что именно вы спрашиваете.:) Возможно, кто-то написал что-то с отражением и / или макросами, которые могли бы обеспечить такую ​​проверку, но не в моих силахНадеемся, что с перечислениями Scala 3 вам никогда не понадобится писать такую ​​функцию.

2 голосов
/ 16 мая 2019

Вот примеры перечисления, предложенные @ LuisMiguelMejíaSuárez и @slouc, которые обеспечивают исчерпание регистра:

перечисление

import enumeratum._

sealed trait Foo extends EnumEntry
object Foo extends Enum[Foo] {
  val values = findValues
  case object Bar extends Foo
  case object Qux extends Foo  
}

Foo.withName("Qux")

Перечисления Scala 3

enum Foo {
  case Bar
  case Qux
}

Foo.enumValueNamed("Qux"))

Оба метода работали нормально даже с параметризованным закрытым типом.

...