我正在努力想出一个能让我做这样的事情的组合器:
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
之类的事情。显然,这最后的尝试并不起作用,因为它的结果总是被定义,并且只会在不存在的键上失败,我只是用它来说明我正在寻找的解决方案如何理想地看起来
想法,有人吗?
答案 0 :(得分:2)
函数本身(pf.apply
)实际上没有被评估两次,但它的isDefinedAt
被评估两次,以便与您的定义成功匹配。这意味着在初始unapply
PartialFunction
中评估两次pf
- s和守卫。
顺便说一句,Scalaz中有一个类似的组合器:pf.first.andThen(_._1)
,但它基本上等同于你的定义。
您可以编写一个小测试,看看pf.isDefinedAt
是否被评估两次并使用pfAdapter
的几种可能实现来运行它:
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))
执行此代码的结果如下:
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)
因此pfAdapter
的第一次实施:Function.unlift((t: (A, T)) => pf.lift(t._1))
实际上 会避免两次评估isDefinedAt
。
这很有效,因为Map.collect
是使用PartialFunction.applyOrElse
实现的,而applyOrElse
的文档是:{/ p>
对于所有部分函数文字,编译器生成一个 applyOrElse实现避免了对模式的双重评估 匹配和守卫。这使得applyOrElse成为了基础 许多操作和方案的有效实施,例如:
...
- 提升和解除不会在每次调用时评估两次源函数