2017-04-15 2 views
2

foldMFoldablecatsで理解しようとしています。リスト内の数字を合計する必要があるとします。実行中の合計が正で、そうでないときに中断する必要があるとします。foldM of Foldableの使い方は?

val sumUp: (Int, Int) => Option[Int] = (x, y) => { 
    println(s"x = $x, y = $y") 
    val sum = x + y 
    if (sum > 0) Some(sum) else None 
} 

scala> val xs = List(1, 2, 3, -2, -5, 1, 2, 3) 
xs: List[Int] = List(1, 2, 3, -2, -5, 1, 2, 3) 

scala> Foldable[Stream].foldM(xs.toStream, 0)(sumUp) 
x = 0, y = 1 
x = 1, y = 2 
x = 3, y = 3 
x = 6, y = -2 
x = 4, y = -5 
res27: Option[Int] = None 

今私は、実行中の合計は= 0 <になり、foldM休憩場所を開始し、入力ストリームの尾を、取得するために新しい機能sumUp2を記述する必要があります。 sumUp2を書くためにどのように

scala> val tail = Foldable[Stream].foldM(xs.toStream, 0)(sumUp2) 
tail: Stream[Int] = Stream(-5, ?) 

scala>tail.toList 
res28: List[Int] = List(-5, 1, 2, 3) 

:たとえば、私はこのような何かを取得する必要がありますか?

答えて

3

あなたができることは、2つの値(タプル内)を累積することです。負の値またはゼロになるまでの実行合計。テールは値を累積し始めます。

val sumUp2: ((Int, List[Int]), Int) => Id[(Int, List[Int])] = (x, y) => { 
    val sum = if (x._1 < 0) x._1 else x._1 + y 
    if (sum > 0) (sum, x._2) else (-1, x._2 ++ List(y)) 
} 

その後、あなたはタプルの2番目の要素から尾を取得することができます:

val xs = List(1, 2, 3, -2, -5, 1, 2, 3) 
val res = Foldable[Stream].foldM(xs.toStream, (0, List[Int]()))(sumUp2) 

println(res._2) 

フィドルhere

+0

残念ながら、 'sumUp2'が' xs'の_all_要素に対して呼び出されていますが、実行中の合計が<= 0のときにfuctionの呼び出しを停止したいと思います。どうもありがとうございました。 – Michael

1

sumUp2を返します。Either[Int, (Int, Int)]を返しました。左側は訪問先の要素の数で、右側は訪問先の要素とラン合計のペアです。

scala> val r = Foldable[Stream].foldM(xs.toStream, (0, 0))(sumUp2) 
sum = 1, y = 1 
sum = 3, y = 2 
sum = 6, y = 3 
sum = 4, y = -2 
sum = -1, y = -5 
r: IntOr[(Int, Int)] = Left(4) 

r: Either[Int, (Int, Int)]を考えると、我々は尾を得ることができます:

scala> r match { case Right(_) => Nil; case Left(n) => xs.drop(n) } 
res63: List[Int] = List(-5, 1, 2, 3) 

我々はsumUp2戻っLeftはそうsumUp2は、すべての要素に対して呼び出されることはありませんfoldM停止していることを知っている

type IntOr[A] = Either[Int, A] 
val sumUp2: ((Int, Int), Int) => IntOr[(Int, Int)] = (pair, y) => { 
    val (size, x) = pair 
    val sum = x + y 
    println(s"sum = $sum, y = $y") 
    if (sum > 0) (size + 1, sum).asRight else size.asLeft 
} 

解決策はうまくいくようですが、私にはうまく見えません。どのように改善しますか?

+0

私は「Either」ソリューションも同様に提案しようとしていました。今私は私のままにしておきます(+1)。 –

+0

ありがとうございます。関数が 'Left'を返すときに' foldM'がどのように停止するかを知っていますか?おそらく、foldMがどのように動作するかを理解するための別個の質問を投稿するでしょう。 – Michael

関連する問題