Pourquoi est fonction partielle <: Fonction Scala?
-
06-09-2019 - |
Question
Dans Scala, la classe PartialFunction[A, B]
est dérivée à partir du type Function[A, B]
(voir Scala Référence, 12.3.3). Cependant, cela semble contre-intuitif pour moi, car un Function
(qui doit être défini pour tous A
) a des exigences plus strictes que PartialFunction
, qui peut être indéfini à certains endroits.
Le problème que je suis tombé sur était que lorsque j'ai une fonction partielle, je ne peux pas utiliser Function
pour étendre la fonction partielle. Par exemple. Je ne peux pas faire:
(pf orElse (_)=>"default")(x)
(Hope la syntaxe est au moins à distance à droite)
Pourquoi est-ce sous-typage fait inverse? Y a-t-il des raisons que j'ai négligé, comme le fait que les types de Function
sont intégrés?
BTW, ce serait aussi bien si Function1 :> Function0
donc je ne doit pas avoir l'argument factice dans l'exemple ci-dessus: -)
Modifier pour clarifier le problème de sous-typage
La différence entre les deux approches peut souligner en examinant deux exemples. Lequel d'entre eux a raison?
One:
val zeroOne : PartialFunction[Float, Float] = { case 0 => 1 }
val sinc = zeroOne orElse ((x) => sin(x)/x) // should this be a breach of promise?
Deux:
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?
Pas de solution correcte
Autres conseils
Parce que Scala (comme dans une langue complète Turing) il n'y a aucune garantie qu'une fonction est totale.
val f = {x : Int => 1 / x}
Cette fonction n'est pas définie à 0. Une fonction partielle est juste une fonction qui promet de vous dire où il est pas défini. Pourtant, Scala rend assez facile à faire ce que vous voulez
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
Si vous préférez, vous pouvez faire func2Partial implicite.
PartialFunction
a des méthodes qui ne Function1
, il est donc le sous-type. Ces méthodes sont isDefinedAt
et orElse
.
Votre vrai problème est que PartialFunction
s ne sont pas inférées parfois quand vous voulez vraiment comme eux d'être. Je suis plein d'espoir qui sera abordé à une date ultérieure. Par exemple, cela ne fonctionne pas:
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" })
Mais cela ne:
scala> pf orElse ({ case x => "default" } : PartialFunction[String,String])
res5: PartialFunction[String,String] = <function>
Bien sûr, vous pouvez toujours faire ceci:
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]
Et maintenant, il est plus comme vous voulez:
scala> pf orElse ((x: String) => "default")
res7: PartialFunction[String,String] = <function>
scala> println(res7("a") + " " + res7("quux"))
foo default