Pergunta

Em Scala, a classe PartialFunction[A, B] é derivado de tipo Function[A, B] (ver Scala Referência, 12.3.3). No entanto, isso parece contra-intuitivo para mim, uma vez que um Function (que precisa ser definido para todos A) tem requisitos mais rigorosos do que um PartialFunction, que pode ser indefinido em alguns lugares.

O problema que eu deparei foi que quando eu tenho uma função parcial, eu não posso usar um Function para estender a função parcial. Por exemplo. Eu não posso fazer:

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

(Hope a sintaxe é pelo menos remotamente direita)

Porque é que este subtipos feito inversamente? Existe algum motivo que eu tenha esquecido, como o fato de que os tipos Function são built-in?

BTW, seria também bom se Function1 :> Function0 então eu não precisa ter o argumento fictício no exemplo acima: -)

Editar para esclarecer o problema subtipagem

A diferença entre as duas abordagens pode ser enfatizado por olhar para dois exemplos. Qual deles está certo?

Um:

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

Dois:

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?

Nenhuma solução correta

Outras dicas

Porque em Scala (como em qualquer linguagem Turing completa) não há nenhuma garantia de que uma função é total.

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

Essa função não é definida em 0. A função parcial é apenas uma função que promessas para lhe dizer onde ele não está definido. Ainda assim, Scala torna fácil o suficiente para fazer o que quiser

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 preferir, você pode fazer func2Partial implícita.

PartialFunction tem métodos que Function1 não, portanto, é o subtipo. Esses métodos são isDefinedAt e orElse.

Seu problema real é que PartialFunctions não são inferidas por vezes, quando você realmente gostaria que eles sejam. Estou esperançoso de que serão abordados em alguma data futura. Por exemplo isso não funciona:

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

Mas isso faz:

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

É claro que você sempre pode fazer isso:

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 agora é mais como você deseja:

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

scala> println(res7("a") + " " + res7("quux"))
foo default
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top