Warum ist Partielle Funktion <: Funktion in Scala?
-
06-09-2019 - |
Frage
In Scala, die PartialFunction[A, B]
Klasse von Typ Function[A, B]
abgeleitet ist (siehe Scala Reference, 12.3.3). Dies scheint jedoch nicht eingängig zu mir, da ein Function
(die für alle A
definiert werden muss) strengere Anforderungen als ein PartialFunction
hat, die an einigen Stellen nicht definiert werden kann.
Das Problem kam ich habe accross war, dass, wenn ich eine Teilfunktion haben, kann ich nicht eine Function
verwenden, um die Teilfunktion zu verlängern. Z.B. Ich kann es nicht tun:
(pf orElse (_)=>"default")(x)
(Hoffnung die Syntax ist mindestens fern rechts)
Warum ist diese Subtyping umgekehrt getan? Gibt es Gründe, die ich übersehen habe, wie die Tatsache, dass die Function
Typen eingebaut sind?
BTW, wäre es auch schön, wenn Function1 :> Function0
so brauche ich nicht das Dummy-Argument in dem obigen Beispiel habe: -)
Bearbeiten, um das Problem zu klären Subtyping
Der Unterschied zwischen den beiden Ansätzen kann durch einen Blick auf zwei Beispiele hervorgehoben werden. Welche von ihnen ist richtig?
One:
val zeroOne : PartialFunction[Float, Float] = { case 0 => 1 }
val sinc = zeroOne orElse ((x) => sin(x)/x) // should this be a breach of promise?
Zwei:
def foo(f : (Int)=>Int) {
print(f(1))
}
val bar = new PartialFunction[Int, Int] {
def apply(x : Int) = x/2
def isDefinedAt(x : Int) = x%2 == 0
}
foo(bar) // should this be a breach of promise?
Keine korrekte Lösung
Andere Tipps
Da in Scala (wie in jedem Turing komplette Sprache) gibt es keine Garantie dafür gibt, dass eine Funktion insgesamt ist.
val f = {x : Int => 1 / x}
Diese Funktion ist nicht definiert auf 0 A Partielle Funktion ist nur eine Funktion, die Ihnen zu sagen, verspricht, wo es nicht definiert ist. Dennoch Scala macht einfach genug, um es zu tun, was Sie wollen
def func2Partial[A,R](f : A => R) : PartialFunction[A,R] = {case x => f(x)}
val pf : PartialFunction[Int, String] = {case 1 => "one"}
val g = pf orElse func2Partial{_ : Int => "default"}
scala> g(1)
res0: String = one
scala> g(2)
res1: String = default
Wenn Sie möchten, können Sie func2Partial implizit machen.
PartialFunction
hat Methoden, die Function1
nicht der Fall, daher der Subtyp ist. Diese Methoden sind isDefinedAt
und orElse
.
Ihr Problem ist, dass PartialFunction
s manchmal nicht geschlossen, wenn Sie wirklich wie sie würden sein. Ich bin zuversichtlich, dass zu einem späteren Zeitpunkt behandelt werden. Zum Beispiel funktioniert das nicht:
scala> val pf: PartialFunction[String, String] = { case "a" => "foo" }
pf: PartialFunction[String,String] = <function>
scala> pf orElse { case x => "default" }
<console>:6: error: missing parameter type for expanded function
((x0$1) => x0$1 match { case (x @ _) => "default" })
Aber das tut:
scala> pf orElse ({ case x => "default" } : PartialFunction[String,String])
res5: PartialFunction[String,String] = <function>
Natürlich könnte man dies immer tun:
scala> implicit def f2pf[T,R](f: Function1[T,R]): PartialFunction[T,R] =
new PartialFunction[T,R] {
def apply(x: T) = f(x)
def isDefinedAt(x: T) = true
}
f2pf: [T,R](f: (T) => R)PartialFunction[T,R]
Und es ist jetzt mehr wie Sie wollen:
scala> pf orElse ((x: String) => "default")
res7: PartialFunction[String,String] = <function>
scala> println(res7("a") + " " + res7("quux"))
foo default