11

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}

andThen はここで期待どおりに動作します。

pf1 andThen pf2 isDefinedAt(x)

trueiffを返しますx == 1(実際にpf2は、PartialFunction である必要はまったくありません)

ただし、次のことを期待していました。

pf1 andThen pf3 isDefinedAt(x)

すべてに対して返さfalseれますx(つまり、pf1 が定義されている場合、pf3 をチェックします) が、pf1 を検証せず、検証するだけです。

最終的には、pf1 andThen pf3 lift(x)常に MatchError になります。None を取得したいのですが… in などの各関数を持ち上げることでこの動作を取得できますが、pf1.lift(x).flatMap(pf3.lift)純粋な PartialFunction API を使用するより簡単な方法はありますか? (そして、各部分関数を個別に持ち上げずに?)

4

3 に答える 3

11

あなたが見ればandThen

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

これにより、受信側が部分関数ではなく関数で構成されます。つまり、は完全に定義されていると予想されますが、 はありません。したがって、結果の部分関数は の動作を変更する必要はなく、最初の部分関数を参照するだけで済みます。kisDefinedAtisDefinedAt

2 つの部分関数を構成する独自の拡張機能を作成できます。

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 が純粋性を強制しないことを考えると、望ましくない副作用を実行することになる可能性があります。

于 2014-01-10T10:27:47.030 に答える
7

flatMapfor PartialFunctionsに相当するものが必要です。

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

これは、副作用があっても期待どおりに機能します。

于 2014-11-22T18:00:48.360 に答える
2

なぜ単純ではないのですか:

def compose[A,B,C](f: PartialFunction[A, B], g: PartialFunction[B, C]) : PartialFunction[A, C] =
Function.unlift(f.andThen(g.lift))
于 2015-03-11T16:01:00.987 に答える