【问题标题】:Is the PartialFunction design inefficient?PartialFunction 设计效率低吗?
【发布时间】:2011-05-03 03:59:49
【问题描述】:

这是我一直想知道的事情。我经常看到这种模式:

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)

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

【问题讨论】:

    标签: scala functional-programming scala-2.8


    【解决方案1】:

    scala-internals 邮件列表中有a conversation going on about this 现在。 Martin Odersky 提出了一种新类型:FunctionWithDefault。 Martin 不仅谈到了运行时损失,还谈到了使用 PartialFunction 的编译时间损失(类文件膨胀):

    首先,我们需要生成两次模式匹配代码,一次是在apply中,一次是在isDefinedAt中。其次,我们还需要执行两次代码,首先测试函数是否适用,然后实际应用。

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

    提出的新类型,FunctionWithDefault 没有isDefinedAt 并且有一个方法:

    trait FunctionWithDefault[-I, +O] {
      def applyOrElse[OO >: O](i : I, default : I => OO) : OO
    }
    

    这有点像Options getOrElse 方法。

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

    【讨论】:

    • 感谢您的详细回复! FunctionWithDefault 听起来正是我想要的。
    • 如果您在性能关键代码中有复杂的匹配语句,那么两次模式匹配肯定会对性能造成很大影响!如果default 是按名称传递的,那么这应该如何比返回选项更有效?也许我应该阅读 scala-internals。
    • 我的默认标志是错误的,奇怪的是它是I => OO
    • 当前 Scala 编译器为 PartialFunction 字面量生成 getOrElse。我认为我们应该始终使用该方法,并且永远不应该手动调用isDefined。对于模式匹配中的PartialFunction,考虑将其转换为提取器:groups.google.com/forum/#!topic/scala-language/g0-hbN5qerQ
    猜你喜欢
    • 2015-08-16
    • 2013-07-15
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    • 2012-09-23
    • 2015-04-25
    • 2011-01-01
    相关资源
    最近更新 更多