46 votes

Pourquoi est-PartialFunction <: Fonction dans Scala?

En Scala, l' PartialFunction[A, B] classe est dérivée de type Function[A, B] (voir Scala de Référence, 12.3.3). Toutefois, cela semble contre-intuitif pour moi, depuis un Function (qui doit être définie pour tous les A) a des exigences plus strictes que d'un PartialFunction, qui peut être indéfini à certains endroits.

Le problème que j'ai trouvé était que lorsque j'ai un partiel de la fonction, je ne peux pas utiliser un Function d'étendre la fonction partielle. Par exemple. Je ne peut pas faire:

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

(Espérons que la syntaxe est au moins à distance de la droite)

Pourquoi est-ce sous-typage fait l'inverse? Existe-il des raisons que j'ai oubliées, comme le fait que l' Function types sont intégrés?

BTW, il serait aussi bien si Function1 :> Function0 donc je n'ai pas l'argument factice dans l'exemple ci-dessus :-)

Edit pour préciser le problème de sous-typage

La différence entre les deux approches peut être mis en évidence en examinant les deux exemples. Lequel d'entre eux est le droit?

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?

34voto

James Iry Points 14192

Parce que dans Scala (comme dans toute Turing langue) il n'y a aucune garantie qu'une Fonction est totale.

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

Cette fonction n'est pas définie en 0. Un PartialFunction est juste une Fonction qui promet de vous dire où il n'est pas défini. Encore, Scala, il est 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, 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.

18voto

extempore Points 8016

PartialFunction a des méthodes qui Fonction1 n'a pas, par conséquent, il est le sous-type. Ces méthodes sont isDefinedAt et orElse.

Votre vrai problème, c'est que PartialFunctions ne sont pas déduit parfois, quand vous voulez vraiment être. J'ai l'espoir que seront traitées à 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 ce n':

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

Bien sûr, vous pourriez 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 vous voulez:

scala> pf orElse ((x: String) => "default")
res7: PartialFunction[String,String] = <function>

scala> println(res7("a") + " " + res7("quux"))
foo default

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X