首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PartialFunction的lift方法的逆

PartialFunction的lift方法的逆
EN

Stack Overflow用户
提问于 2011-05-06 02:09:33
回答 6查看 3.5K关注 0票数 22

PartialFunctionlift方法将PartialFunction转换为返回Option结果的Function

是否存在将Function1[A, Option[B]]转换为PartialFunction[A, B]的反向操作

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2011-05-06 02:42:27

不是在库中,但它很容易构建。然而,isDefinedAt将不得不全面评估函数,使其比典型的通过模式匹配构建的部分函数更昂贵,还可能导致不想要的副作用。

代码语言:javascript
复制
scala> def unlift[A, B](f : (A => Option[B])) = new PartialFunction[A,B] {
     |    def isDefinedAt(x : A) = f(x).isDefined
     |    def apply(x : A) = f(x).get
     | }
unlift: [A,B](f: (A) => Option[B])java.lang.Object with PartialFunction[A,B]
scala> def f(x : Int) = if (x == 1) Some(1) else None
f: (x: Int)Option[Int]
scala> val g = unlift(f)
g: java.lang.Object with PartialFunction[Int,Int] = <function1>
scala> g.isDefinedAt(1)
res0: Boolean = true
scala> g.isDefinedAt(2)
res1: Boolean = false
scala> g(1)
res2: Int = 1
scala> g(2)
java.util.NoSuchElementException: None.get
    at scala.None$.get(Option.scala:262)
    at scala.None$.get(Option.scala:260)
    at $anon$1.apply(<console>:7)
    at scala.Function1$class.apply$mcII$sp(Function1.scala:39)
    at $anon$1.apply$mcII$sp(<console>:5)
    at .<init>(<console>:9)
    at .<clinit>(<console>)
    at RequestResult$.<init>(<console>:9)
    at RequestResult$.<clinit>(<console>)
    at RequestResult$scala_repl_result(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
    at scala.tools....

纯粹主义者可能还会用try/catch块包装isDefinedAt,以便在异常时返回false。

票数 6
EN

Stack Overflow用户

发布于 2011-05-07 16:47:18

很难从一系列scala名人中获得所有这些优秀的答案,但如果您想了解标准库中的答案,可以在scala.Function伴生对象中找到它。(在2.9中。)

代码语言:javascript
复制
/** Turns a function `A => Option[B]` into a `PartialFunction[A, B]`.  Important note:
 *  this transformation implies the original function will be called 2 or more
 *  times on each logical invocation, because the only way to supply an implementation
 *  of isDefinedAt is to call the function and examine the return value.
 *
 *  @param   f    a function T => Option[R]
 *  @return       a partial function defined for those inputs where
 *                f returns Some(_) and undefined where f returns None.
 *  @see PartialFunction#lift
 */
def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = new PartialFunction[T, R] {
  def apply(x: T): R = f(x).get
  def isDefinedAt(x: T): Boolean = f(x).isDefined
  override def lift: T => Option[R] = f
}
票数 39
EN

Stack Overflow用户

发布于 2011-05-06 03:07:24

为了用一个更复杂的例子来构建James的答案,我在我的东西库- the -Scala- library -forgot(或者不信任-you- with )中有以下代码:

代码语言:javascript
复制
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)

大部分代码用于确保函数求值被缓存(只要apply紧跟在isDefinedAt之后)。使用示例:

代码语言:javascript
复制
scala> val f = (x: Int) => if (x>=0) Some(x) else None
f: (Int) => Option[Int] = <function1>

scala> Array(-2,-1,0,1,2).collect(f.drop)
res0: Array[Int] = Array(0, 1, 2)

缓存有助于加快速度并避免双重副作用问题(至少在apply之前使用isDefinedAt时,以及函数在返回None时忽略副作用时)。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5902266

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档