9

BooleanOption[_]Validation[_, _]Either[_, _]などのように、ScalazはさまざまなADTに対してfoldという名前のメソッドを提供します。このメソッドは基本的にADTのすべての可能なケースに対応する関数を取ります。換言すれば、以下に示すパターンマッチ:同時に、同じでの動作がある折りたたみオプション、いずれかなどの関係は何ですか?

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 

:いくつかの例

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

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

は、と等価ですTraversable[_]タイプの名前。そのエレメントで特定の操作を実行しているコレクションをトラバースし、結果の値を累積します。 fold/catamorphism - 例えば、

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つの操作が同じ名前で識別されますか?私は両者の間に類似点や関係がないのを見ている。私は何が欠けていますか?

答えて

7

私は、あなたが持っている問題は、それらの実装に基づいてこれらのものを見ているということです。

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

だから、Optionに、それはBにいくつかの値に可能なすべてのケースを減少させ、そしてそれを返しますのは、sが倍Option」を考えてみましょう、今

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

Option[A] = None 
      | Some el: A 

:タイプのこの単純な表現を考えてみましょう。我々はList[A]に、そこに再帰呼び出しを持っていることが

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

注、:今、Listのため同じものを見てみましょう。私たちは、何とかそれを折るする必要がありますが、我々はList[A]fold[B]は常にBを返しますので、私たちはこのようにそれを書き換えることができます知っている:折りたたみは、それが常に返されますので、我々は、BList[A]を置き換え、言い換えれば

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

をa B、タイプ署名がfoldの場合さて、foldRightのための署名を入力しのは、Scalaの(ユースケース)を見てみましょう:

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

言って、それが何かを思い出させてくれありませんか?

+0

ああ、再帰的に適用する必要があります!ありがとう、ありがとう。 – missingfaktor

+2

[catamorphismに関するWikipediaのページ](http://en.wikipedia.org/wiki/Catamorphism)では、「関数型プログラミングでは、関数型プログラミングは関数型プログラミングから任意の代数的データにわたるリストのフォールドを一般化したものです初期代数として記述することができます。その後、Erik Meijerの論文「バナナ、レンズ、封筒、有刺鉄線による機能プログラミング」を指摘する。トピックをよりよく理解するためには、その論文を読むべきだと思います。 – missingfaktor

+1

@missingfaktor、ウィキペディアのページの最後には、非常にアクセス可能であるような変態に関する6つのブログがあります。私は今それを読んでいる。それはF#ですが、それはあなたにとって問題ではないと確信しています。 – huynhjl

5

「折りたたみ」を「操作によってコンテナ内のすべての値を凝縮し、シード値で凝縮する」と考えて、Optionを最大で1つの値を持つことができるコンテナと考えると、意味をなさない実際に

foldLeftは同じシグネチャを持っており、あなたはなしVS空のリストにそれを使用する場合とまったく同じ結果が得られるようになりますし、いくつかの対のみ一つの要素を持つリストに:

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標準ライブラリのListOptionの両方で定義されています(実際には両方が特性から継承されていると思います)。そして再び、あなたはいくつかのようシングルトンリストに同じ結果を得る:

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

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

私はOption/EitherにScalazからfoldの/ etc約100%わからないんだけど、あなたはそこに良い点を上げます。私が以前使っていた「折りたたみ」とはかなり違う署名と操作をしているようです。

関連する問題