Pourquoi PartialFunction <: Fonction dans Scala?

Dans Scala, la PartialFunction[A, B] est dérivée du type Function[A, B] (voir référence Scala, 12.3.3). Cependant, cela me semble contre-intuitif, car une Function (qui doit être définie pour tous les A ) a des exigences plus ssortingctes qu’une fonction PartialFunction , qui peut être indéfinie à certains endroits.

Le problème que j’ai rencontré est que lorsque j’ai une fonction partielle, je ne peux pas utiliser une Function pour étendre la fonction partielle. Par exemple. Je ne peux pas le faire:

 (pf orElse (_)=>"default")(x) 

(J’espère que la syntaxe est au moins à droite)

Pourquoi ce sous-typage est-il inversé? Y a-t-il des raisons que j’ai négligées, comme le fait que les types de Function soient intégrés?

BTW, ce serait aussi bien si Function1 :> Function0 donc je n’ai pas besoin de l’argument factice dans l’exemple ci-dessus 🙂

Editer pour clarifier le problème de sous-typage

La différence entre les deux approches peut être soulignée en examinant deux exemples. Lequel d’entre eux a raison?

Un:

 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? 

Parce que dans Scala (comme dans tout langage complet de Turing), il n’y a aucune garantie qu’une fonction soit totale.

 val f = {x : Int => 1 / x} 

Cette fonction n’est pas définie à 0. Une fonction partielle est simplement une fonction qui promet de vous indiquer où elle n’est pas définie. Pourtant, Scala rend assez facile de faire ce que vous voulez

 def func2Partial[A,R](f : A => R) : PartialFunction[A,R] = {case x => f(x)} val pf : PartialFunction[Int, Ssortingng] = {case 1 => "one"} val g = pf orElse func2Partial{_ : Int => "default"} scala> g(1) res0: Ssortingng = one scala> g(2) res1: Ssortingng = default 

Si vous préférez, vous pouvez rendre implicite func2Partial.

PartialFunction a des méthodes que Function1 n’a pas, donc c’est le sous-type. Ces méthodes sont isDefinedAt et orElse .

Votre vrai problème est que les fonctions PartialFunction ne sont pas inférées parfois quand vous les aimeriez vraiment. J’espère que cela sera abordé à une date ultérieure. Par exemple, cela ne fonctionne pas:

 scala> val pf: PartialFunction[Ssortingng, Ssortingng] = { case "a" => "foo" } pf: PartialFunction[Ssortingng,Ssortingng] =  scala> pf orElse { case x => "default" } :6: error: missing parameter type for expanded function ((x0$1) => x0$1 match { case (x @ _) => "default" }) 

Mais cela fait:

 scala> pf orElse ({ case x => "default" } : PartialFunction[Ssortingng,Ssortingng]) res5: PartialFunction[Ssortingng,Ssortingng] =  

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 c’est plus comme tu veux:

 scala> pf orElse ((x: Ssortingng) => "default") res7: PartialFunction[Ssortingng,Ssortingng] =  scala> println(res7("a") + " " + res7("quux")) foo default