将 PartFunctions 与 andthen 在 Scala 中链接



让我们重用Daily scala的例子:

type PF = PartialFunction[Int,Int]
val pf1 : PF = {case 1 => 2}                      
val pf2 : PF = {case 2 => 3}                      

让我们补充一下:

val pf3 : PF = {case 3 => 4}

然后按预期在这里工作:

pf1 andThen pf2 isDefinedAt(x)

返回true iff x == 1(实际上,pf2根本不需要是 PartialFunction)

但是,我期望:

pf1 andThen pf3 isDefinedAt(x)

将返回所有xfalse(即定义了 iff pf1,请检查 pf3),但它没有并且只验证 pf1。

最后,pf1 andThen pf3 lift(x)总是会导致匹配错误。我宁愿得到没有...我可以通过提升每个函数(例如在 pf1.lift(x).flatMap(pf3.lift) 中)来获得此行为,但是使用纯 Partial Function API 是否有更简单的方法?(并且没有单独提升每个部分功能?

如果你看andThen

def andThen[C](k: (B) => C): PartialFunction[A, C]

这将接收器与函数而不是部分函数组成。也就是说,k期望完全定义,但它没有isDefinedAt。因此,得到的偏函数不需要改变isDefinedAt的行为,它仍然只需要咨询第一个偏函数。

您可以编写自己的扩展来组合两个分部函数:

implicit class ComposePartial[A, B](pf: PartialFunction[A, B]) {
  def collect[C](that: PartialFunction[B, C]): PartialFunction[A, C] =
    new PartialFunction[A, C] {
      def apply(a: A): C = that(pf(a))
      def isDefinedAt(a: A) = pf.isDefinedAt(a) && {
        val b = pf(a)
        that.isDefinedAt(b)
      }
    }
}
pf1 collect pf2 isDefinedAt(1)  // true
pf1 collect pf3 isDefinedAt(1)  // false

问题是你必须调用 pf(a) ,所以鉴于 Scala 不强制纯洁,你最终可能会不想要地执行副作用。

你需要相当于

flatMapPartialFunction s。

implicit class CollectPartial[A, B](f: PartialFunction[A, B]) {
    def collect[C](g: PartialFunction[B, C]) = Function.unlift { a: A =>
        f.lift(a).flatMap(g.lift)
    }
}

像使用它一样

val a: PartialFunction[String, Int] = ...
val b: PartialFunction[Int, Char] = ...
val c: PartialFunction[String, Char] = a collect b

即使有副作用,这也按预期工作。

为什么不简单地:

def compose[A,B,C](f: PartialFunction[A, B], g: PartialFunction[B, C]) : PartialFunction[A, C] =
Function.unlift(f.andThen(g.lift))

相关内容

  • 没有找到相关文章

最新更新