Scala orElse如何处理部分函数
使用Scala orElse如何处理部分函数,scala,functional-programming,read-eval-print-loop,partialfunction,Scala,Functional Programming,Read Eval Print Loop,Partialfunction,使用PartialFunction 在我看来: val a = PartialFunction[String, Unit] { case "hello" => println("Bye") } val b: PartialFunction[Any, Unit] = a.orElse(PartialFunction.empty[Any, Unit]) a("hello") // "Bye" a("bogus") // MatchError b("bogus") // Nothing
PartialFunction
在我看来:
val a = PartialFunction[String, Unit] {
case "hello" => println("Bye")
}
val b: PartialFunction[Any, Unit] = a.orElse(PartialFunction.empty[Any, Unit])
a("hello") // "Bye"
a("bogus") // MatchError
b("bogus") // Nothing
b(true) // Nothing
有道理,但这不是它的行为方式,我很难理解为什么,因为类型签名似乎表明了我在上面暴露的内容
以下是我对Scala 2.11.2的观察记录:
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val a = PartialFunction[String, Unit] {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1>
scala> a("hello")
Bye
scala> a("bye")
scala.MatchError: bye (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36)
... 33 elided
scala> val b = a.orElse(PartialFunction.empty[Any, Unit])
b: PartialFunction[String,Unit] = <function1>
scala> b("sdf")
scala.MatchError: sdf (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.PartialFunction$OrElse.apply(PartialFunction.scala:162)
... 33 elided
PartialFunction.empty[A,B]
相当于:
{
case x: Nothing => x
}
(此类型检查,因为Nothing
是a
和B
的子类型)
或者,相当于:
{
// note: this is probably not a valid Scala code for a partial function
// but, as PartialFunction.empty's name suggests, it's an *empty* block
}
这与任何东西都不匹配
.orElse
可以理解为简单地将两个PartialFunction
s中的case语句列表串联起来。因此,在您的情况下,a.orElse(PartialFunction.empty[Any,Unit]
表示:
{ case "hello" => println("Bye") } orElse { /* no cases here */ }
这简化为:
{ case "hello" => println("Bye") }
或
因此,匹配错误
是显而易见的
注意,还提到empty
总是抛出MatchError
据我猜测,您需要一个始终匹配的
PartialFunction
。标准库中没有为此命名的方法,但为什么应该有。您只需编写
{ case _ => () }
您正在使用
PartialFunction
对象应用方法,该方法的定义如下:
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
基本上,它采用函数形式a
到B
,并自动将其包装在case语句中,问题是您也在传递case,我不能100%确定接下来会发生什么,您可以尝试将函数传递给apply,也可以很容易地尝试不使用apply方法:
scala> val a: PartialFunction[String, Unit] = {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1>
scala> val b: PartialFunction[String, Unit] = {
| case _ => println("default")
| }
b: PartialFunction[String,Unit] = <function1>
scala> b("123")
default
scala>vala:PartialFunction[字符串,单位]={
|案例“你好”=>println(“再见”)
| }
a:部分函数[字符串,单位]=
scala>val b:PartialFunction[字符串,单位]={
|案例=>println(“默认”)
| }
b:部分函数[字符串,单位]=
scala>b(“123”)
违约
您还可以扩展trait并实现
apply
和isDefined
,如图所示。您的尝试有一些错误,但首先让我们看看一个可行的实现:
scala> val a: PartialFunction[String, Unit] = { case "hello" => println("bye") }
a: PartialFunction[String,Unit] = <function1>
scala> val b: PartialFunction[Any, Unit] = { case _ => println("fallback") }
b: PartialFunction[Any,Unit] = <function1>
scala> val c = a.orElse(b)
c: PartialFunction[String,Unit] = <function1>
scala> c("hello")
bye
scala> c("foo")
fallback
如何定义它:
val wrong = PartialFunction[String, Unit] {
case "hello" => println("bye")
}
如果您查看PartialFunction.apply的定义
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
您将看到,它为任何x
定义了一个分部函数,并将给定的f
函数应用于它。现在,您的{case“hello”=>println(“bye”)}
是f
参数,因此您大概会得到以下(显然出乎意料的)分部函数
:
val wrong: PartialFunction[String, Unit] = {
case x => x match {
case "hello" => println("bye")
}
因此,当您询问它是否已定义时,它将始终返回true,因为它是为任何字符串定义的:
wrong.isDefinedAt("hello") // true (ok)
wrong.isDefinedAt("whatever") // true (sure?)
但是当你尝试应用它时
wrong("hello") // bye (ok)
wrong("whatever") // MatchError (BOOM!)
你在内部比赛中落后了
由于orElse
根据已定义的结果决定是否调用“else”,因此它失败的原因显而易见
2.空无一物!
直截了当地说:
def empty[A,B]:部分功能[A,B]
域为空的分部函数。任何调用空分部函数的尝试都会引发scala.MatchError
异常
您要查找的PartialFunction
(它不再是真正的部分功能)是:
val fallback: PartialFunction[Any, Unit] = { case _ => println("fallback") }
或者——只是为了表明我们从错误中吸取了教训-
val fallback = PartialFunction[Any, Unit] { _ => println("fallback") }
如果我定义valb:PartialFunction[String,Unit]=a.orElse(PartialFunction[String,Unit]{case}=>println(“123”)}
,如果我定义b(“123”),我仍然会得到匹配异常
,无论如何,我认为你是对的,PartialFunction.empty
匹配Nothing
@EndeNeu,你是对的,有两个错误。这个答案抓住了第二个,但是匹配错误发生了before@GabrielePetronella如果我在评论中定义了b
,那么Nothing
beca就没有匹配项使用我不再使用PartialFunction.empty
了,我有两个单独的PF,一个匹配“hello”
和另一个匹配的\u
@EndeNeu正如我在回答中解释的,a
定义不正确,这就是问题所在。你说的对,问题在于apply方法。你在任意x上定义了一个部分函数,然后在该x上应用给定的函数。有关详细解释,请参阅我的回答。为什么我会这样做s是c
PartialFunction[String,Unit]
的类型,而不是PartialFunction[Any,Unit]
?@欠准确,如果你看一下orElse
的定义,它实际上应该拒绝将b
作为一个参数,因为Any
不是String
的子类型。它以某种方式将b
视为PartialFunction[字符串,单位]
并使其工作。无论如何,orElse
返回的类型将永远不会比原始函数所组成的更宽。@Underveragent,我已经对此进行了一段时间的推理,我必须说我感到困惑。orElse
肯定会拒绝b
。我问了一个问题,看看是否有人能理解这一点输出:
wrong("hello") // bye (ok)
wrong("whatever") // MatchError (BOOM!)
val fallback: PartialFunction[Any, Unit] = { case _ => println("fallback") }
val fallback = PartialFunction[Any, Unit] { _ => println("fallback") }