3

ディープ パターン マッチングのユース ケースで部分関数を試してみたいと思います。これは、最初は (もちろん) Some(Some(3)) を適用した後は機能しませんでしたが、代わりに定義されているように見えました:

def deepTest : PartialFunction [Option[Option[Int]], Int] = {
    case Some(v) => v match {
      case None => 3 
    }
    case None => 1
}

入れ子になったパターン マッチングを分離することで、物事はより簡単になると思いました。

def deepTestLvl1 : PartialFunction [Option[Option[Int]], Option[Int]] = {
  case Some(v) => v
  case None => Some(1)
}


def deepTestLvl2 : PartialFunction [Option[Int], Int] = {
  case None => 3
}

しかし、結果は次のとおりでした。

scala> (deepTestLvl1 andThen deepTestLvl2) isDefinedAt(Some(Some(3)))
res24: Boolean = true

適用後:

scala> (deepTestLvl1 andThen deepTestLvl2) (Some(Some(3)))
scala.MatchError: Some(3) (of class scala.Some)
    at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:248)
    at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:246)
    at $anonfun$deepTestLvl2$1.applyOrElse(<console>:7)
    at $anonfun$deepTestLvl2$1.applyOrElse(<console>:7)
        ....
    at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:83)
    at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
    at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105)
    at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

私は何か間違ったことをしていますか?順番に deepTestLvl{1,2} を合成したときに isDefinedAt を 2 回呼び出して正解を出すべきではありませんか?

4

2 に答える 2

3

とても良い質問です。

ソースをチェックして、内部で何が起こっているか見てみましょう:

override def andThen[C](k: B => C): PartialFunction[A, C] =
  new AndThen[A, B, C] (this, k)

ここでandThen は、 Partial Function を想定していないこともわかります。結果を変換する任意の Function が実行されます。次の理由により、コードが機能しますtrait PartialFunction[-A, +B] extends (A => B)。これは実際にはドキュメントにあります:

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

この部分関数を、この部分関数の結果に適用される変換関数で構成します。

C変換関数の結果の型。

k変換関数

xは、引数をにマップするこの部分関数と同じドメインを持つ部分関数をk(this(x))​​します。

PartialFunctionしたがって、ロビンが言ったように、関数を適用する必要があるため、現在、希望する方法で sをチェーンする方法はありません。計算コストが高いだけでなく、副作用もある可能性があり、これはより大きな問題です。

アップデート

あなたが探している実装をまとめました。慎重に使用してください!既に述べたように、コードに副作用がある場合、問題が発生します。

implicit class PartialFunctionExtension[-A, B](pf: PartialFunction[A, B]) {
  def andThenPf[C](pf2: PartialFunction[B, C]) = new PfAndThen(pf, pf2)

  class PfAndThen[+C](pf: PartialFunction[A, B], nextPf: PartialFunction[B, C]) extends PartialFunction[A, C] {
    def isDefinedAt(x: A) = pf.isDefinedAt(x) && nextPf.isDefinedAt(pf.apply(x))

    def apply(x: A): C = nextPf(pf(x))
  }
}

試してみます:

deepTestLvl1.andThenPf(deepTestLvl2).isDefinedAt(Some(Some(3)))  // false
deepTestLvl1.andThenPf(deepTestLvl2).isDefinedAt(Some(None))     // true
deepTestLvl1.andThenPf(deepTestLvl2).apply(Some(None))           // 3
于 2013-11-23T19:35:29.313 に答える