Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 部分函数的逆';s提升法_Scala - Fatal编程技术网

Scala 部分函数的逆';s提升法

Scala 部分函数的逆';s提升法,scala,Scala,PartialFunction的lift方法将PartialFunction转换为函数返回选项结果 是否存在与此相反的操作,将Function1[a,Option[B]]转换为PartialFunction[a,B]?不在库中,但很容易构建。然而,isDefinedAt必须对函数进行全面评估,使其比通过模式匹配构建的部分函数的典型成本更高,并且还可能导致不必要的副作用 scala> def unlift[A, B](f : (A => Option[B])) = new Partia

PartialFunction
lift
方法将PartialFunction转换为
函数
返回
选项
结果


是否存在与此相反的操作,将
Function1[a,Option[B]]
转换为
PartialFunction[a,B]

不在库中,但很容易构建。然而,isDefinedAt必须对函数进行全面评估,使其比通过模式匹配构建的部分函数的典型成本更高,并且还可能导致不必要的副作用

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....
scala>def unlift[A,B](f:(A=>Option[B])=newpartialfunction[A,B]{
|def isDefinedAt(x:A)=f(x)。isDefined
|def应用(x:A)=f(x)。获取
| }
unlift:[A,B](f:(A)=>Option[B])java.lang.Object与PartialFunction[A,B]
scala>def(x:Int)=如果(x==1)一些(1)其他无
f:(x:Int)选项[Int]
scala>val g=unlift(f)
g:java.lang.Object与PartialFunction[Int,Int]=
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
在scala.None$.get(Option.scala:262)
在scala.None$.get(Option.scala:260)
在$anon$1.应用(:7)
在scala.Function1$class.apply$mcII$sp处(Function1.scala:39)
在$anon$1。应用$mcII$sp(:5)
在。(:9)
在
请求时结果$。(:9)
请求时结果$()
请求时结果$scala_repl_result()
在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处
位于sun.reflect.NativeMethodAccessorImpl.invoke(未知源)
在sun.reflect.DelegatingMethodAccessorImpl.invoke处(未知源)
位于java.lang.reflect.Method.invoke(未知源)
在scala.tools.nsc.transparer$Request$$anonfun$loadand run$1$$anonfun$apply$17.apply(transparer.scala:988)
在scala。工具。。。。

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

以James的答案为基础

还可以缓存在
isDefinedAt
中生成的结果,然后在调用
apply
时返回该结果,从而避免重复执行


然而,Scala并没有强制执行纯函数,因此很容易找到现实生活中的例子,在这些例子中,任何一种解压策略都会产生出人意料的结果。因此,通常不建议将某些内容“取消”到
部分函数中,以James的答案为基础,使用一个更复杂的示例,我的Scala库中有以下代码,这些代码被Scala库遗忘了(或不信任你):

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

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)
scala>valf=(x:Int)=>如果(x>=0)一些(x)其他没有
f:(Int)=>选项[Int]=
scala>数组(-2,-1,0,1,2).收集(f.drop)
res0:Array[Int]=数组(0,1,2)

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

很难从一系列scala灯具中找到所有这些好的答案,但是,如果您想了解标准库中的一个,它位于scala.Function companion对象中。(在2.9中)


我们应该始终使用部分函数文本来构建
PartialFunction
,因为对于
PartialFunction
来说,正确实现
applyOrElse
太简单了

因此,正确的
unlift
应按如下方式执行:

// Use AnyVal to avoid the indirect reference to f
class Extractor[A, B](val f: A => Option[B]) extends AnyVal {
  def unapply(a: A) = f(a)
}

def unlift[A, B](f: A => Option[B]): PartialFunction[A, B] = {
  val LocalExtractor = new Extractor(f)

  // Create the PartialFunction from a partial function literal
  { case LocalExtractor(b) => b }
}

你可以使用
函数。unlift
,。

你是说返回
部分函数[a,B]
的东西,不是吗?可能重复
部分函数的
lift
正是我要找的。谢谢!:)谢谢,双重评估的需要解释了为什么它从图书馆里消失了。哇,这看起来很吓人。保证它不是线程安全的。它可能有它的用途,但是。。。“保重!”乔纳奇里斯托弗萨恩瓦尔德说,“的确如此。和大多数使用缓存的东西一样,它不是线程安全的。我喜欢这个答案。我看到了两种潜在的线程安全解决方案,请回顾一下:一种是将
tested
arg
ans
封装在元组或case类中,然后
DroppedFunction
将始终具有内部一致的状态。另一种方法是完全避免这个问题,并确保在任何多线程上下文中,
dropped函数
是在作用域的本地新创建的。@samthebest-使用case类可以提供一致性,但不能阻止同一函数的多个应用程序。在
synchronized
块中包装
isDefinedAt
apply
稍微好一点,但这不会阻止用户在一个线程中调用
isDefinedAt
,然后在另一个线程中调用另一个线程,然后在第一个线程中使用
apply
,并从第二个线程中获取结果。。最好不要在多线程上下文中使用它,因为您无法确保人们使用
applyOrElse
(这可能是安全的)。您没有实现
getOrElse
。看有趣的。这是否避免了当前(29-2.11)库实现中出现的双重执行?如果是,为什么库实现没有以这种方式实现它?
/** 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
}
// Use AnyVal to avoid the indirect reference to f
class Extractor[A, B](val f: A => Option[B]) extends AnyVal {
  def unapply(a: A) = f(a)
}

def unlift[A, B](f: A => Option[B]): PartialFunction[A, B] = {
  val LocalExtractor = new Extractor(f)

  // Create the PartialFunction from a partial function literal
  { case LocalExtractor(b) => b }
}