很有可能要知道函数是否在某个时刻定义,计算其价值的重要部分必须完成.在PartialFunction,在实现时isDefined和apply,这两种方法将不得不这样做.怎么办这个常见的工作成本很高?
有可能缓存其结果,希望在isDefined之后调用apply.绝对丑陋.
我经常希望那PartialFunction[A,B]是Function[A, Option[B]],这显然是同构的.或许,可能还有另一种方法PartialFunction,比方说applyOption(a: A): Option[B].对于一些mixins,实现者可以选择实现isDefined和apply或applyOption.或者所有这些都是安全的,性能明智.isDefined在呼叫申请之前进行测试的客户将被鼓励使用applyOption.
但事实并非如此.库中的一些主要方法,其中包括collect集合中的一些PartialFunction.是否有一种干净(或不那么干净)的方式来避免支付isDefined和apply之间重复的计算?
另外,applyOption(a: A): Option[B]方法合理吗?在未来的版本中添加它听起来可行吗?它值得吗?
为什么缓存会出现这样的问题?在大多数情况下,您有本地计算,因此只要为缓存编写一个包装器,就不必担心它。我的实用程序库中有以下代码:
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)
Run Code Online (Sandbox Code Playgroud)
然后,如果我有一个昂贵的计算,我会编写一个函数方法A => Option[B]并执行诸如(f _).drop在收集或其他操作中使用它之类的操作。(如果您想内联执行此操作,您可以创建一个接受A=>Option[B]并返回部分函数的方法。)
(相反的转换——从PartialFunction到A => Option[B]——称为提升,因此称为“下降”;我认为“取消提升”是相反操作的更广泛使用的术语。)