Domanda

In Scala, la classe PartialFunction[A, B] è derivato dal tipo Function[A, B] (vedi Scala di riferimento, 12.3.3). Tuttavia, questo sembra controintuitivo per me, dal momento che un Function (che deve essere definita per tutto A) ha requisiti più severi di un PartialFunction, che può essere definita per alcuni posti.

Il problema che ho mai incontrato era che quando ho una funzione parziale, non posso usare un Function per estendere la funzione parziale. Per esempio. Non posso fare:

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

(La speranza la sintassi è almeno in remoto destra)

Perché questo sottotipo fatto in senso inverso? Ci sono ragioni che ho trascurato, come il fatto che i tipi di Function sono incorporati?

A proposito, sarebbe anche bello se Function1 :> Function0 quindi non è soggetta all'obbligo dei argomento fittizio nell'esempio di cui sopra: -)

Modifica per chiarire il problema di sottotipo

La differenza tra i due approcci può essere sottolineato, cercando in due esempi. Quale di loro è giusto?

Uno:

val zeroOne : PartialFunction[Float, Float] = { case 0 => 1 }
val sinc = zeroOne orElse ((x) => sin(x)/x) // should this be a breach of promise?

Due:

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?

Nessuna soluzione corretta

Altri suggerimenti

A causa a Scala (come in qualsiasi lingua completa Turing) non v'è alcuna garanzia che una funzione è totale.

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

Questa funzione non è definito a 0. Una funzione parziale è solo una funzione che promette di dirvi dove non è definito. Eppure, Scala rende facile abbastanza per fare quello che vuoi

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

Se si preferisce, si può fare func2Partial implicita.

PartialFunction ha metodi che Function1 non, quindi è il sottotipo. Tali metodi sono isDefinedAt e orElse.

Il vero problema è che PartialFunctions non vengono dedotte a volte quando vuoi davvero che siano. Sono fiducioso che verrà affrontato in un prossimo futuro. Per esempio questo non funziona:

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" })

Ma questo fa:

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

Naturalmente si può sempre fare questo:

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]

E ora è più come si desidera:

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

scala> println(res7("a") + " " + res7("quux"))
foo default
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top