11

Scalazは、、、などのさまざまなADTにちなんで名付けられたメソッドを提供します。foldこのBooleanメソッドは、基本的に、その特定のADTのすべての可能なケースに対応する関数を取ります。つまり、以下に示すパターンマッチです。Option[_]Validation[_, _]Either[_, _]

x match {
  case Case1(a, b, c) => f(a, b, c)
  case Case2(a, b) => g(a, b)
  .
  .
  case CaseN => z
}

と同等です:

x.fold(f, g, ..., z)

いくつかの例:

scala> (9 == 8).fold("foo", "bar")
res0: java.lang.String = bar

scala> 5.some.fold(2 *, 2)
res1: Int = 10

scala> 5.left[String].fold(2 +, "[" +)
res2: Any = 7

scala> 5.fail[String].fold(2 +, "[" +)
res6: Any = 7

同時に、Traversable[_]タイプに同じ名前の操作があり、コレクションをトラバースしてその要素に対して特定の操作を実行し、結果値を累積します。例えば、

scala> List(2, 90, 11).foldLeft("Contents: ")(_ + _.toString + " ")
res9: java.lang.String = "Contents: 2 90 11 "

scala> List(2, 90, 11).fold(0)(_ + _)
res10: Int = 103

scala> List(2, 90, 11).fold(1)(_ * _)
res11: Int = 1980

これらの2つの操作が同じ名前(fold/ catamorphism)で識別されるのはなぜですか?私は2つの間に類似点/関係を見ることはできません。私は何が欠けていますか?

4

2 に答える 2

7

あなたが抱えている問題は、これらのものを型ではなく実装に基づいて見ることだと思います。この単純なタイプの表現を考えてみましょう:

List[A] = Nil 
        | Cons head: A tail: List[A]

Option[A] = None
          | Some el: A

Optionでは、の折り方を考えてみましょう:

fold[B] = (noneCase: => B, someCase: A => B) => B

したがって、 onOptionでは、考えられるすべてのケースを のある値に減らし、それBを返します。では、同じことを見てみましょうList:

fold[B] = (nilCase: => B, consCase: (A, List[A]) => B) => B

ただし、そこに再帰呼び出しがあることに注意してくださいList[A]fold[B]どうにか折り畳まなければなりませんが、 aList[A]は常に return になることがわかっているBので、次のように書き直すことができます。

fold[B] = (nilCase: => B, consCase: (A, B) => B) => B

言い換えれば、型シグネチャが与えられた場合、折りたたみは常に を返すため、 に置き換えましList[A]た。では、Scala の (ユース ケース) の型シグネチャを見てみましょう。BBfoldfoldRight

foldRight[B](z: B)(f: (A, B) ⇒ B): B

ねえ、それはあなたに何かを思い出させますか?

于 2011-12-16T21:30:54.280 に答える
5

「折り畳み」を「シード値を使用して操作を通じてコン​​テナー内のすべての値を凝縮する」と考え、オプションを最大で 1 つの値を持つことができるコンテナーと考え​​ると、これは理にかなっています。 .

実際、foldLeftは同じシグネチャを持ち、空のリストと None、および要素が 1 つだけのリストと Some で使用すると、まったく同じ結果が得られます。

scala> val opt : Option[Int] = Some(10)
opt: Option[Int] = Some(10)

scala> val lst : List[Int] = List(10)
lst: List[Int] = List(10)

scala> opt.foldLeft(1)((a, b) => a + b)
res11: Int = 11

scala> lst.foldLeft(1)((a, b) => a + b)
res12: Int = 11

foldも Scala 標準ライブラリの両方Listで定義されてOptionおり、同じシグネチャで定義されています (実際、どちらもトレイトから継承していると思います)。また、Singleton リストでも Some と同じ結果が得られます。

scala> opt.fold(1)((a, b) => a * b)
res25: Int = 10

scala> lst.fold(1)((a, b) => a * b)
res26: Int = 10

foldfrom Scalaz on Option/ /etcについては 100% 確信が持てませんがEither、あなたはそこに良い点を挙げています。私が慣れ親しんでいる「折る」とはかなり違うサインや操作をしているようです。

于 2011-12-17T01:47:09.780 に答える