在 PartialFunction 的 isDefined 和 Apply 中都发生了昂贵的计算 [英] costly computation occuring in both isDefined and Apply of a PartialFunction

查看:28
本文介绍了在 PartialFunction 的 isDefined 和 Apply 中都发生了昂贵的计算的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很可能要知道某个函数是否在某个时刻定义,必须完成计算其值的重要部分.在 PartialFunction 中,当实现 isDefinedapply 时,两种方法都必须这样做.这个普通的工作成本高怎么办?

It is quite possible that to know whether a function is defined at some point, a significant part of computing its value has to be done. In a PartialFunction, when implementing isDefined and apply, both methods will have to do that. What to do is this common job is costly?

有缓存其结果的可能,希望在isDefined之后调用apply.绝对丑.

There is the possibility of caching its result, hoping that apply will be called after isDefined. Definitely ugly.

我经常希望 PartialFunction[A,B]Function[A, Option[B]],这显然是同构的.或者,PartialFunction 中可能还有另一种方法,比如 applyOption(a: A): Option[B].对于一些 mixins,实现者可以选择实现 isDefined 和 apply 或 applyOption.或者所有这些都是为了安全起见,性能明智.鼓励在调用 apply 之前测试 isDefined 的客户端改用 applyOption.

I often wish that PartialFunction[A,B] would be Function[A, Option[B]], which is clearly isomorphic. Or maybe, there could be another method in PartialFunction, say applyOption(a: A): Option[B]. With some mixins, implementors would have a choice of implementing either isDefined and apply or applyOption. Or all of them to be on the safe side, performance wise. Clients which test isDefined just before calling apply would be encouraged to use applyOption instead.

然而,事实并非如此.库中的一些主要方法,其中集合中的collect 需要一个PartialFunction.是否有一种干净(或不那么干净)的方法来避免为在 isDefined 和 apply 之间重复的计算付费?

However, this is not so. Some major methods in the library, among them collect in collections require a PartialFunction. Is there a clean (or not so clean) way to avoid paying for computations repeated between isDefined and apply?

另外,applyOption(a:A):Option[B]方法合理吗?在未来版本中添加它听起来可行吗?值得吗?

Also, is the applyOption(a: A): Option[B] method reasonable? Does it sound feasible to add it in a future version? Would it be worth it?

推荐答案

为什么缓存会出现这样的问题?在大多数情况下,您有一个本地计算,因此只要您为缓存编写一个包装器,您就不必担心它.我的实用程序库中有以下代码:

Why is caching such a problem? In most cases, you have a local computation, so as long as you write a wrapper for the caching, you needn't worry about it. I have the following code in my utility library:

  class DroppedFunction[-A,+B](f: A => Option[B]) extends PartialFunction[A,B] {
    private[this] var tested = false
    private[this] var arg: A = _
    private[this] var ans: Option[B] = None
    private[this] def cache(a: A) {
      if (!tested || a != arg) {
        tested = true
        arg = a
        ans = f(a)
      }
    }        
    def isDefinedAt(a: A) = {
      cache(a)
      ans.isDefined
    }
    def apply(a: A) = {
      cache(a)
      ans.get
    }
  }
  class DroppableFunction[A,B](f: A => Option[B]) {
    def drop = new DroppedFunction(f)
  }
  implicit def function_is_droppable[A,B](f: A => Option[B]) = new DroppableFunction(f)

然后如果我有一个昂贵的计算,我会写一个函数方法 A =>Option[B] 并执行诸如 (f _).drop 之类的操作以在收集或诸如此类的东西中使用它.(如果你想内联,你可以创建一个接受 A=>Option[B] 并返回一个部分函数的方法.)

and then if I have an expensive computation, I write a function method A => Option[B] and do something like (f _).drop to use it in collect or whatnot. (If you wanted to do it inline, you could create a method that takes A=>Option[B] and returns a partial function.)

(相反的转换——从 PartialFunctionA => Option[B]——被称为提升,因此下降";解除"是,我认为,相反操作的更广泛使用的术语.)

(The opposite transformation--from PartialFunction to A => Option[B]--is called lifting, hence the "drop"; "unlift" is, I think, a more widely used term for the opposite operation.)

这篇关于在 PartialFunction 的 isDefined 和 Apply 中都发生了昂贵的计算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆