前回のScalaz Effects IOに引き続き、今度はSTで遊んでみようと思います。
今回、参考にさせていただいたのは前回同様こちらのslideshareと
http://www.slideshare.net/SanshiroYoshida/scalaz-effects
Scalazに付属しているサンプル
ExampleST.scala
です。
STを使うと、可変の変数と配列をモナドの構文で扱えます。すごい役に立つか?と聞かれると、ちょっと微妙な気がしないでもないですが…。
下準備は、IOの時と同じで以下をimport。
import scalaz._ import scalaz.Scalaz._ import scalaz.effects._
まずは可変変数を扱う例。
val f1 = new Forall[({type λ[S] = ST[S, Int]})#λ] { def apply[A]: ST[A, Int] = { for { v <- newVar[A, Int](10) modified <- v.mod(_ + 1) r <- modified.read } yield r } } {io(runST(f1).toString) >>= putStrLn}.unsafePerformIO
STを使うと、Forallがつきまとうらしいです…。今回は、対象の変数をInt型、初期値10で作成しています。この部分ですね。
v <- newVar[A, Int](10)
次に、1を加算しています。
modified <- v.mod(_ + 1)
最後に値を読み出し、yieldに渡します。
r <- modified.read
ちなみに、modもreadもSTRefというクラスのメソッドです。
STから値を得るには、runSTというメソッドを使用します。値を出力する時にIOを使用しているのは、ご愛嬌。
{io(runST(f1).toString) >>= putStrLn}.unsafePerformIO
実行すると、こうなります。
11
続いて、STでは配列も扱うことができます。以下がその例です。
val f2 = new Forall[({type λ[S] = ST[S, ImmutableArray[String]]})#λ] { def apply[A]: ST[A, ImmutableArray[String]] = { for { arr <- newArr[A, String](5, "Languages") _ <- arr.write(0, "Scala") _ <- arr.write(1, "Java") _ <- arr.write(2, "Clojure") _ <- arr.write(3, "Ceylon") _ <- arr.update((a, b: String) => b |+| a, 4, "Programming ") r <- arr.freeze } yield r } } runST(f2).toArray.foreach(println)
最初に、要素数が5で、全て初期値「Languages」が設定された配列を作成します。
arr <- newArr[A, String](5, "Languages")
この配列に対しては、値の上書きや
_ <- arr.write(0, "Scala")
元の値を使用しつつ、更新したりすることができます。
_ <- arr.update((a, b: String) => b |+| a, 4, "Programming ")
ちなみに、|+|というのはSemigroupのメソッドです。Stringの場合は+演算子と同じですね。
最後にfreezeを呼び出し、ImmutableArrayに変換し、これをSTで包んで戻り値とします。
r <- arr.freeze
write、update、freezeはSTArrayクラスのメソッドです。
このサンプルを実行すると、こうなります。
Scala Java Clojure Ceylon Programming Languages
しかし、このST、どう使うと効果的なのかな??
今回のサンプルコード全体です。
import scalaz._ import scalaz.Scalaz._ import scalaz.effects._ object EffectsSTExample extends App { val f1 = new Forall[({type λ[S] = ST[S, Int]})#λ] { def apply[A]: ST[A, Int] = { for { v <- newVar[A, Int](10) modified <- v.mod(_ + 1) r <- modified.read } yield r } } {io(runST(f1).toString) >>= putStrLn}.unsafePerformIO val f2 = new Forall[({type λ[S] = ST[S, ImmutableArray[String]]})#λ] { def apply[A]: ST[A, ImmutableArray[String]] = { for { arr <- newArr[A, String](5, "Languages") _ <- arr.write(0, "Scala") _ <- arr.write(1, "Java") _ <- arr.write(2, "Clojure") _ <- arr.write(3, "Ceylon") _ <- arr.update((a, b: String) => b |+| a, 4, "Programming ") r <- arr.freeze } yield r } } runST(f2).toArray.foreach(println) }