Surjectivity check when return type is sealed

自闭症网瘾萝莉.ら 提交于 2020-01-01 09:50:40

问题


Scala can warn when pattern match on a sealed type is not exhaustive, however can we check that a function returns all cases when the return type is sealed? For example, consider the following ADT

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

Then function f: Foo => String on the algebraic data type Foo

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

raises warning

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

Is it possible to raise a similar non-exhaustion warning when return type is an ADT such as in the following implementation of f: String => Foo:

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

回答1:


Maybe this is not really an answer, but it's too long for a comment anyway.

Pattern matching and function return values are two different things. Former operates on the type level, latter on the value level. When you pattern match on Bar, you're pattern matching on the type (just like e.g. Int). But when you return Bar, you're returning the case object value (just like e.g. 42).

Surjective function is defined as:

For every member y of the codomain, there exists at least one member x of the domain, such that f(x) = y.

Now it's easy to see why this check is not feasible / possible. What if your Bar wasn't a case object, but a class? E.g.

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

You would need to expect every possible value of Bar to be used (e.g. name = "John", surname = "Smith", age = 42).

Of course, this is not what you intended; what you described is a scenario where each subtype has exactly one inhabitant, because Bar and Qux are basically enums, and I can see why such a check might make sense to you. But it would have to be implemented for the general case of arbitrary number of inhabitants per (sub)type - it would need to verify that codomain contains at least one value of type Bar, at least one value of type Qux etc. which doesn't sound very useful.

As I said, this is not really an answer, but I wanted to give you an insight into what exactly it is that you're asking. :) Perhaps someone wrote something with reflection and/or macros which could provide such a check, but not to my knowledge. Hopefully with Scala 3 enums you will never need to write such a function anyway.




回答2:


Here are enumeration examples suggested by @LuisMiguelMejíaSuárez and @slouc which do provide case exhaustion:

enumeratum

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 Enumerations

enum Foo {
  case Bar
  case Qux
}

Foo.enumValueNamed("Qux"))

Both methods worked fine even with parameterised sealed type.



来源:https://stackoverflow.com/questions/56152173/surjectivity-check-when-return-type-is-sealed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!