为什么定义了这个PartialFunction,但在Scala中应用后仍然崩溃(正确)?
我想尝试使用深度模式匹配用例的部分函数。这一点最初(当然)在应用了一些(一些(3))之后不起作用,但似乎被定义为:为什么定义了这个PartialFunction,但在Scala中应用后仍然崩溃(正确)?,scala,partialfunction,Scala,Partialfunction,我想尝试使用深度模式匹配用例的部分函数。这一点最初(当然)在应用了一些(一些(3))之后不起作用,但似乎被定义为: def deepTest : PartialFunction [Option[Option[Int]], Int] = { case Some(v) => v match { case None => 3 } case None => 1 } 我认为通过解耦嵌套模式匹配,事情会更容易: def deepTestLvl1 :
def deepTest : PartialFunction [Option[Option[Int]], Int] = {
case Some(v) => v match {
case None => 3
}
case None => 1
}
我认为通过解耦嵌套模式匹配,事情会更容易:
def deepTestLvl1 : PartialFunction [Option[Option[Int]], Option[Int]] = {
case Some(v) => v
case None => Some(1)
}
def deepTestLvl2 : PartialFunction [Option[Int], Int] = {
case None => 3
}
但结果如下:
scala> (deepTestLvl1 andThen deepTestLvl2) isDefinedAt(Some(Some(3)))
res24: Boolean = true
申请后:
scala> (deepTestLvl1 andThen deepTestLvl2) (Some(Some(3)))
scala.MatchError: Some(3) (of class scala.Some)
at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:248)
at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:246)
at $anonfun$deepTestLvl2$1.applyOrElse(<console>:7)
at $anonfun$deepTestLvl2$1.applyOrElse(<console>:7)
....
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:83)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
scala>(deepTestLvl1和deepTestLvl2)(一些(一些(3)))
scala.MatchError:Some(3)(属于scala.Some类)
在scala.PartialFunction$$anon$1.apply处(PartialFunction.scala:248)
在scala.PartialFunction$$anon$1.apply处(PartialFunction.scala:246)
在$anonfun$deepTestLvl2$1.applyOrElse(:7)
在$anonfun$deepTestLvl2$1.applyOrElse(:7)
....
位于scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:83)
在scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)中
位于scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105)
位于scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
我做错什么了吗?当我按顺序编写deepTestLvl{1,2}并给出正确答案时,isDefinedAt不应该被调用两次吗?对
生成的部分函数
进行isDefinedAt
的原因是它实际上没有将第一个部分函数应用于它的参数,这可能是一个昂贵的手术
这种行为可能会让人绊倒,而且没有文档记录——您可能需要提交一个补丁来添加文档
另外,我的猜测是,deepTest
之所以会这样做,是因为部分函数定义的源代码中最外层的match
,并且只有最外层的匹配,被认为是用于定义的目的-但是您必须检查scalac
的源代码才能确定,我想。这是一个很好的问题
让我们检查来源,看看封面下发生了什么:
override def andThen[C](k: B => C): PartialFunction[A, C] =
new AndThen[A, B, C] (this, k)
我们可以在这里观察到,,然后
甚至不需要部分函数,任何转换结果的函数都可以。您的代码可以工作,因为:trait PartialFunction[-A,+B]扩展了(A=>B)
。这实际上可以在以下内容中找到:
def和第[C](k:(B)⇒ C) :部分功能[A,C]
将此分部函数与应用于此分部函数结果的转换函数组合
C转换函数的结果类型
k变换函数
返回与此分部函数具有相同域的分部函数,该分部函数将参数x
映射到k(此(x))
因此,目前没有办法以您希望的方式链接PartialFunction
s,因为正如Robin所说,这需要应用该函数。除了计算成本高之外,它还可能产生副作用,这是一个更大的问题
更新
拼凑出一个您正在寻找的实现小心使用正如我已经提到的,如果您的代码有副作用,它将导致问题:
implicit class PartialFunctionExtension[-A, B](pf: PartialFunction[A, B]) {
def andThenPf[C](pf2: PartialFunction[B, C]) = new PfAndThen(pf, pf2)
class PfAndThen[+C](pf: PartialFunction[A, B], nextPf: PartialFunction[B, C]) extends PartialFunction[A, C] {
def isDefinedAt(x: A) = pf.isDefinedAt(x) && nextPf.isDefinedAt(pf.apply(x))
def apply(x: A): C = nextPf(pf(x))
}
}
试一试:
deepTestLvl1.andThenPf(deepTestLvl2).isDefinedAt(Some(Some(3))) // false
deepTestLvl1.andThenPf(deepTestLvl2).isDefinedAt(Some(None)) // true
deepTestLvl1.andThenPf(deepTestLvl2).apply(Some(None)) // 3
不幸的是,Scala语言规范中没有正确地记录这一点-请参阅,它可以工作,但没有真正完整地解释。有人知道一个实际的引用,它正确地记录了Scala部分函数的当前行为吗?@RobinGreen请检查我的答案。它没有文档记录,因为它不是
的定义方式,
。@krivachy.akos我指的是deepTest
。啊,在这种情况下,我认为您必须实现两个部分函数的所有组合<代码>案例部分(无)=>3和案例部分(部分(v))=>v
。这并不太优雅,特别是考虑到案例数量可以呈指数增长的事实。在Coursera的“反应式编程原理”中,Martin Odersky解释说,实际上只考虑最外层的匹配。