scala - PartialFunction 设计效率低下吗?

标签 scala functional-programming scala-2.8

这是我想了一段时间的事情。我经常看到这种模式:

if (pf.isDefinedAt(in)) pf(in)

通过将其分解为两个单独的调用,所有在#isDefinedAt 中求值的模式也将在#apply 中求值。例如:
object Ex1 {
  def unapply(in: Int) : Option[String] = {
    println("Ex1")
    if (in == 1) Some("1") else None
  }
}

object Ex2 {
  def unapply(in: Int) : Option[String] = {
    println("Ex2")
    if (in == 2) Some("2") else None
  }
}

val pf : PartialFunction[Int,String] = {
  case Ex1(result) => result
  case Ex2(result) => result
}

val in = 2

if (pf.isDefinedAt(in)) pf(in)

哪个打印
Ex1
Ex2
Ex1
Ex2
res52: Any = 2

在最坏的情况下,当您的模式最后匹配时,您在调用 PartialFunction 时已经评估了您的模式/提取器两次。当匹配不仅仅是简单的类或列表模式匹配的自定义提取器时,这可能会变得效率低下(例如,如果您有一个解析 XML 文档并返回一些值对象的提取器)

PartialFunction#lift 遭受同样的双重评估:
scala> pf.lift(2)
Ex1
Ex2
Ex1
Ex2
res55: Option[String] = Some(2)

有没有办法有条件地调用一个函数,如果它被定义而不可能两次调用所有的提取器?

最佳答案

a conversation going on about this现在在 Scala 内部 邮寄名单。 Martin Odersky 提出了一种新类型:FunctionWithDefault . Martin 不仅谈到了运行时的惩罚,还谈到了使用 PartialFunction 的编译时惩罚(类文件膨胀)。 :

First, we need to generate the pattern matching code twice, once in the apply and then again in the isDefinedAt. Second, we also need to execute the code twice, first to test whether the function is applicable, and then to actually apply it.



您的问题的答案基本上是"is",并且这种行为( PartialFunction )也不会由于向后兼容性问题而改变(例如,如果 isDefinedAt 有副作用怎么办)。

正在提议的新型,FunctionWithDefault没有 isDefinedAt并有一个方法:
trait FunctionWithDefault[-I, +O] {
  def applyOrElse[OO >: O](i : I, default : I => OO) : OO
}

这有点像 Option s getOrElse方法。

我不得不说,像往常一样,我无法想象这种低效率会在绝大多数情况下造成任何类型的性能问题。

关于scala - PartialFunction 设计效率低下吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4064859/

相关文章:

scala - 阅读 Parquet 时是否有可能保持列顺序?

scala - 将用于Scala的µTest(微型测试)集成到Gradle项目中

scala - 为什么 scala 编译器允许不带参数调用 PartialFunction?

java - 谁能解释一下什么是状态和可变数据?

scala - 根据参数值和函数参数类型推断通用父类(super class)型

scala - 有没有一种方法可以链接以getOrElse一样的方式返回Option-Type的方法,但保留option-type

compiler-construction - 在F#中使用Roslyn

f# - F#中时间戳的并行排序-功能性方式?

scala - 如何在scala中将文件存储为数组?

scala - 如何在列表中找到匹配的元素并将其映射为Scala API方法?