7

私は Scala コードで、特にスレッド状態のためにモナディック スタイルを使用することを計画しています。これは、3 つのモナド関数を組み合わせた単純な例です (副作用のみを考慮します)。

import scalaz._
import Scalaz._

object MonadTest {
  def adder(i: Int) = State[String, Int] ({str: String => (str + i.toString + " ", i) })
  val oneTwoThreeMonad = for {
    m1 <- adder(1)
    m2 <- adder(2)
    m3 <- adder(3)
  } yield m3
  oneTwoThreeMonad("start: ")._1 //String = "start: 1 2 3 "
}

これはすべて自明であり、期待どおりに機能します。Listしかし、このアプローチが私にとって本当に役立つためには、それをfor-comprehensionと組み合わせられるようにしたいと考えています。これは、私が何を意味するかを示すための少しの (動作しない) コードです。

val list = List(1, 2, 3)

val oneTwoThreeBis = for {
  i <- list
  mx <- adder(i)
} yield mx

基本的に、 a からの引数に基づいてモナドを結合できるようにしたいと考えていますList- の各要素でモナド関数を実行し、list副作用を累積します。サンプルの構文が機能しないことは理解しており、機能しない理由もわかります。クリーンでエレガントな等価物を探しているだけです。

scalaz モナド トランスフォーマーを使用して、より具体的にはこれを実現できると確信してStateTいますが、どうやってそれを行うのかはよくわかりません。

PS。私は Scalaz 7.0-M3 を使用しているため、構文は最も一般的な 6.x とは少し異なる場合があります。

4

1 に答える 1

9

あなたが探しているものを正確に理解できるかどうかはわかりませんが、ここのようなものが必要なようtraverseです(traverseHaskellのより一般的なバージョンはどこにありますかmapM):

import scalaz._, Scalaz._

def adder(i: Int) = State[String, Int](str => (str + i.toString + " ", i))

List(1, 2, 3).traverseS(adder)("start: ")._1

これにより、期待どおりに次のように出力されます。

res0: String = "start: 1 2 3 "

かなり厄介な型パラメーターを書き出す必要を避けるためにtraverseS(のS略)を使用していることに注意してください。ただし、トラバース可能なものにモナディック関数をマップする場合は、より一般的に役立ちます。Statetraverse

これがあなたが望んでいたものではない場合、私は例を挙げてうれしいですStateT、しかしそれはあなたがタイプの何かを持っていることになるでしょうList[(String, Int)]

于 2012-12-11T00:23:31.163 に答える