首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PartialFunction适配器

PartialFunction适配器
EN

Stack Overflow用户
提问于 2016-05-18 11:11:26
回答 1查看 104关注 0票数 1

我正试图想出一个组合器,可以让我做这样的事情:

代码语言:javascript
复制
 def pfAdapter(pf: PartialFunction[String, String]): PartialFunction[(String,String), String]) = { 
   case (a,b) if(pf.isDefinedAt(a)) => pf(a)
 }

基本上,我有一个Map[String, String],并希望使用它作为一个接受两个参数的PartialFunction --忽略第二个元素,并使用第一个元素作为键。

上面的方法是可行的,但我不喜欢这样一个事实:pf本质上被评估了两次(可能没有办法),而且它并不“优雅”.我想知道是否有某种我不知道的组合器会让我做一些像{ _._1 } andThen pf这样的事情。显然,最后一次尝试不起作用,因为它的结果总是被定义的,而且只会在不存在的键上失败,我只是用它来说明我正在寻找的解决方案是如何理想的。

有人想过吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-18 13:02:54

函数本身(pf.apply)实际上不会被计算两次,但是它的isDefinedAt会被计算两次,以便与您的定义成功匹配。这意味着评估两次unapply-s和初始PartialFunction pf中的警卫。

顺便说一下,Scalaz中有一个combinator做了类似的事情:pf.first.andThen(_._1),但它基本上等同于您的定义。

您可以编写一个小测试,查看是否对pf.isDefinedAt进行了两次评估,并使用几个可能的pfAdapter实现运行它。

代码语言:javascript
复制
object Unapply {
  def unapply(s: String): Boolean = {
    println(s"unapplying on $s")
    s == "1"
  }
}

val m = Map("1" -> 1, "2" -> 2)
def pf: PartialFunction[String, String] = {
  case Unapply() => "11"
}

def pfAdapter1[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] =
  Function.unlift((t: (A, T)) => pf.lift(t._1))

def pfAdapter2[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] =
  new PartialFunction[(A, T), B] {
    def isDefinedAt(arg: (A, T)) = pf.isDefinedAt(arg._1)
    def apply(arg: (A, T)) = pf(arg._1)
  }

def pfAdapter3[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] = {
  case (a,b) if pf.isDefinedAt(a) => pf(a)
}

def pfAdapter4[A, B, T](pf: PartialFunction[A, B]): PartialFunction[(A, T), B] = {
  import scalaz.Scalaz._
  pf.first.andThen(_._1)
}

println(m collect pfAdapter1(pf))
println(m collect pfAdapter2(pf))
println(m collect pfAdapter3(pf))
println(m collect pfAdapter4(pf))

执行此代码的结果如下:

代码语言:javascript
复制
unapplying on 1
unapplying on 2
List(11)
unapplying on 1
unapplying on 1
unapplying on 2
List(11)
unapplying on 1
unapplying on 1
unapplying on 2
List(11)
unapplying on 1
unapplying on 1
unapplying on 2
List(11)

因此,pfAdapterFunction.unlift((t: (A, T)) => pf.lift(t._1))的第一个实现实际上避免了两次评估isDefinedAt

这是可行的,因为Map.collect是用PartialFunction.applyOrElse实现的,applyOrElse文档声明:

对于所有的部分函数文本,编译器生成一个applyOrElse实现,这避免了模式匹配器和保护程序的双重评估。这使得applyOrElse成为许多操作和场景高效实现的基础,例如: ..。

  • 每次调用时,lift和unlift不对源函数进行两次评估。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37297874

复制
相关文章

相似问题

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