簡體   English   中英

在Scala中使用andThen鏈接PartialFunctions

[英]Chaining PartialFunctions with andThen in 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)

將為所有x返回false (即,iff pf1已定義,檢查pf3),但它不會且僅驗證pf1。

最后, pf1 andThen pf3 lift(x)總是導致MatchError。 我寧願得到None ...我可以通過提升每個函數來獲得這種行為,例如在pf1.lift(x).flatMap(pf3.lift)但使用純PartialFunction 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沒有強制執行純度,你最終可能會不必要地執行副作用。

PartialFunction需要等效的flatMap

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))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM