6

これは次のフォローアップです:文字列のセットのセットを Scala のデカルト積に拡張する

アイデアはあなたが取りたいということです:

val sets = Set(Set("a","b","c"), Set("1","2"), Set("S","T"))

そして戻ってきます:

Set("a&1&S", "a&1&T", "a&2&S", ..., "c&2&T")

一般的な解決策は次のとおりです。

def combine[A](f:(A, A) => A)(xs:Iterable[Iterable[A]]) =
    xs.reduceLeft { (x, y) => x.view.flatMap {a => y.map(f(a, _)) } } 

次のように使用されます。

val expanded = combine{(x:String, y:String) => x + "&" + y}(sets).toSet

Set[Set[A]]理論的には、 type の入力を取得して a を取得する方法があるはずSet[B]です。つまり、要素を結合しながら型を変換するということです。

使用例は、(上記のように) 文字列のセットを取り込み、それらの連結の長さを出力することです。のf関数は、combine次のような形式になります。

(a:Int, b:String) => a + b.length 

私は実装を思いつくことができませんでした。誰か答えがありますか?

4

2 に答える 2

9

コンバイナー関数にマッピングを実行させたい場合は、 a を使用できますfoldが、Craig が指摘したように、シード値を指定する必要があります。

def combine[A, B](f: B => A => B, zero: B)(xs: Iterable[Iterable[A]]) =         
    xs.foldLeft(Iterable(zero)) { 
       (x, y) => x.view flatMap { y map f(_) } 
    }

このようなシード値が必要であるという事実は、コンバイナー/マッパー関数の型(B, A) => B(または、カリー化された関数としてB => A => B) に由来します。A明らかに、最初に遭遇したものをマッピングするには、 B.

Zero型クラスを使用することで、呼び出し元にとっていくらか簡単にすることができます。

trait Zero[T] {
   def zero: T
}
object Zero {
   implicit object IntHasZero extends Zero[Int] {
      val zero = 0
   }
   // ... etc ...
}

次に、combineメソッドを次のように定義できます。

def combine[A, B : Zero](f: B => A => B)(xs: Iterable[Iterable[A]]) =         
    xs.foldLeft(Iterable(implicitly[Zero[B]].zero)) { 
       (x, y) => x.view flatMap { y map f(_) }
    }

使用法:

combine((b: Int) => (a: String) => b + a.length)(sets)

ScalazZero型クラスを提供し、関数型プログラミングのための他の多くの機能も備えています。

于 2010-12-23T00:56:08.327 に答える
7

あなたが直面している問題は、 reduce(Left|Right) が型を変更できない関数 (A, A) => A を取ることです。(B, A) ⇒ B を取る foldLeft のようなものが必要で、異なるタイプの出力を蓄積できます。ただし、フォールドにはシード値が必要であり、ここでは空のコレクションにすることはできません。xs を頭と尾に分解し、頭の iterable を Iterable[B] にマップし、マップされた頭、尾、およびいくつかの関数 (B, A) => B で foldLeft を呼び出す必要があります。価値があるよりも面倒なように思えるので、事前にすべてのマッピングを行います.

def combine[A, B](f: (B, B) => B)(g: (A) => B)(xs:Iterable[Iterable[A]]) =
  xs.map(_.map(g)).reduceLeft { (x, y) => x.view.flatMap {a => y.map(f(a, _)) } }
val sets = Set(Set(1, 2, 3), Set(3, 4), Set(5, 6, 7))
val expanded = combine{(x: String, y: String) => x + "&" + y}{(i: Int) => i.toString}(sets).toSet
于 2010-12-22T23:31:08.793 に答える