CLOVER🍀

That was when it all began.

Scalaz Effects ST

前回の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)
}