scalaz effects
TRANSCRIPT
![Page 1: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/1.jpg)
Scalaz.effects
使い方など、簡単に説明します
よしだ(@halcat0x15a)
![Page 2: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/2.jpg)
scalaz.effectsとは
● IOモナドやSTモナドなど、Haskellライクな入出力や可変状態を扱うパッケージ。
● package object effectsに関数やimplicitが定義され
ているので、それをimportすることでIOモナドやSTモナドが使える。
● Haskellの関数に対応しているので、"haskell 関数
名"でググればだいたい出てくる。
![Page 3: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/3.jpg)
IOについて
● IO[A]は値であり、アクションといわれる。
● 関数はアクションを返すだけで、実行はしない。
● unsafePerformIOが呼ばれてはじめて実行される。
● 実行後、型Aの結果が返る。
![Page 4: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/4.jpg)
主な標準入出力関数
● def putChar (c: Char): IO[Unit] ● def putStr (s: String): IO[Unit] ● def putStrLn (s: String): IO[Unit] ● def putOut [A] (a: A): IO[Unit]● def getChar : IO[Char] ● def readLn : IO[String]
![Page 5: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/5.jpg)
主なIO[A]の主なメソッド
● def flatMap [B] (f: (A) ⇒ IO[B]): IO[B]● def map [B] (f: (A) ⇒ B): IO[B] ● def bracket [B, C] (after: (A) ⇒ IO[B])(during: (A) ⇒ IO[C]):
IO[C]○ このメソッドはduringを適用したあと、afterを呼びます。○ afterは例外に関係なく呼ばれます。
● def catchLeft : IO[Either[Throwable, A]] ● def except (handler: (Throwable) ⇒ IO[A]): IO[A] ● def unsafePerformIO : A
○ アクションを実行し、値を返します。
![Page 6: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/6.jpg)
標準入出力関数の使い方
import scalaz._import effects._import Scalaz._
val i = for { _ <- putStrLn("Greetings! What is your name?") // 文字列を出力 inpStr <- readLn // 一行読み込む outStr = "Welcome to Scalaz, " |+| inpStr |+| "!" // 新しい文字列を作る _ <- putStrLn(outStr) // 作った文字列を出力} yield () // 戻り値はUnit
i.unsafePerformIO // ここで実行
![Page 7: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/7.jpg)
結果
scala> :load io.scalaLoading io.scala...import scalaz._import effects._import Scalaz._i: scalaz.effects.IO[Unit] = scalaz.effects.IO$$anon$2@10f436Greetings! What is your name?SanshiroWelcome to Scalaz, Sanshiro!
![Page 8: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/8.jpg)
標準の関数と比べて
● readLn >>= putStrLnとかできてカッコイイ!● 参照透過!
○ しかし、ScalaはIOを特別に見てくれるわけではないので、unsafePerformIOを書かなければいけない。
● 例外に対するメソッドがたくさんある。
● unsafePerformIOをタイプするのが面倒。
![Page 9: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/9.jpg)
STについて
● 安全に可変状態を扱うためのもの。
● 可変参照がつくれる。
● 可変配列がつくれる。
● STモナド内でしか変更できない。
● runSTによってSTを実行し、値を取り出します。
![Page 10: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/10.jpg)
STモナドのための主な関数
● def newVar [S, A] (a: A): ST[S, STRef[S, A]]
● def newArr [S, A] (size: Int, z: A)(implicit arg0: Manifest[A]): ST[S, STArray[S, A]]
● def returnST [S, A] (a: ⇒ A): ST[S, A]
● def runST [A] (f: Forall[[S]ST[S, A]]): A
![Page 11: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/11.jpg)
STRefとSTArrayの主なメソッド
● STRef○ def write (a: ⇒ A): ST[S, STRef[S, A]] ○ def mod [B] (f: (A) ⇒ A): ST[S, STRef[S, A]] ○ def read : ST[S, A]
● STArray
○ def write (i: Int, a: A): ST[S, STArray[S, A]]○ def update [B] (f: (A, B) ⇒ A, i: Int, v: B): ST[S, Unit]○ def read (i: Int): ST[S, A] ○ def freeze : ST[S, ImmutableArray[A]]
![Page 12: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/12.jpg)
STモナド(STRef)
import scalaz._import effects._import Scalaz._
val f = new Forall[({type X[S] = ST[S, String]})#X] { def apply[A] = for { v <- newVar[A, String]("Scala") // 参照を作る _ <- v.mod(_ |+| "Chan") // 値を取り出して文字を連結 s <- v.read // 値を取り出す } yield s}
runST(f) // 実行
![Page 13: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/13.jpg)
結果
scala> :load st.scalaLoading st.scala...import scalaz._import effects._import Scalaz._f: java.lang.Object with scalaz.Forall[[S]scalaz.effects.ST[S,java.lang.String]] = $$$$2c9d7a9074166de3bf8b66cf7c45a3ed$$$$anon$1@c8354eres17: java.lang.String = ScalaChan
![Page 14: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/14.jpg)
STモナド(STArray)
import scalaz._import effects._import Scalaz._import ImmutableArray._
val f = new Forall[({type X[S] = ST[S, ImmutableArray[String]]})#X] { def apply[A] = for { v <- newArr[A, String](5, "Scala") // 長さ5の配列を作り"Scala"で埋める _ <- v.write(1, "Clojure") // 1番目を"Clojure"に書き換え _ <- v.write(2, "JRuby") // 2番目を"JRuby"に書き換え _ <- v.update(_ |+| (_: String), 3, "Chan") // 3番目を取り出し、連結 a <- v.freeze // ImmutableArrayで取り出す } yield a}
runST(f).foreach(println) // 実行
![Page 15: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/15.jpg)
結果
scala> :load st.scalaLoading st.scala...import scalaz._import effects._import Scalaz._import ImmutableArray._f: java.lang.Object with scalaz.Forall[[S]scalaz.effects.ST[S,scalaz.ImmutableArray[java.lang.String]]] = $anon$1@e5e138ScalaClojureJRubyScalaChanScala
![Page 16: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/16.jpg)
利点は?
● HaskellではSTモナドを使えば安全に可変状態を扱えるみたいですが、Scalaではvarがあるので必要がない気がします。
● Forall書くのがめんどいです。
● newVar[RealWorld, A]みたいに書けばIO[A]に暗黙
的に変換してくれるので、unsafePerformIOで値を取り出せます。
● ScalaでSTモナドとはいったい・・・・・
![Page 17: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/17.jpg)
ファイル入力(rReadLn)
import scalaz._import effects._import Scalaz._ val file = new java.io.File("test.txt")
val i = for { r <- bufferFile(file) // ファイルを開く _ <- { // ファイルの終わりまで再帰的に出力する関数 def f(i: IO[Option[String]]): IO[Unit] = i >>= { case Some(s) => putStrLn(s) >|> f(rReadLn(r)) case None => ().pure[IO] // 推論してくれないのが悲しい } f(rReadLn(r)) } _ <- closeReader(r) // 閉じる} yield () i.unsafePerformIO
![Page 18: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/18.jpg)
ファイル入力(Iteratee)
import scalaz._import effects._import Scalaz._import IterV._
val file = new java.io.File("test.txt")
val i = for { xs <- for { // ファイルを読み込み、List[String]に変換 f <- getFileLines(file)(collect[String, List]) } yield f.run // IO[List[String]]が返る _ <- xs.traverse_(putStrLn) // リストの内容を出力} yield ()
i.unsafePerformIO
![Page 19: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/19.jpg)
結果
scala> :load iter.scalaLoading iter.scala...import scalaz._import effects._import Scalaz._import IterV._file: java.io.File = test.txti: scalaz.effects.IO[Unit] = scalaz.effects.IO$$anon$2@cfb016The source for Scalaz is now hosted on GitHub - http://github.com/scalaz/scalaz
Scalaz is a library written in the Scala Programming Language. The intention of Scalaz is to include general functions that are not currentlyavailable in the core Scala API. The scalaz-core module depends only on the core Scala API and the core Java 2 Standard Edition API. Scalazis released under a BSD open source licence making it compatible with the licence of the Scala project.
Scalaz 6.0.1 was released in June 2011, targeting Scala 2.8.1 and 2.9.0.1.
![Page 20: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/20.jpg)
IterVについて
● def collect [A, F[_]] (implicit mon: Monoid[F[A]], pr: Pure[F]): IterV[A, F[A]]
○ F[A]に変換します。○ 基本的にはこれを使うといいです。
● def drop [E] (n: Int): IterV[E, Unit] ○ n個の要素を消費します
● def head [E] : IterV[E, Option[E]] ○ 先頭要素を消費し、取得します
● def peek [E] : IterV[E, Option[E]] ○ 先頭要素を消費せず、取得します
● def length [E] : IterV[E, Int] ○ 要素全体の数を取得します。
![Page 21: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/21.jpg)
Iterateeのもっと詳しい説明
● 続きはWebで☆
● スミマセン。LTでやれる気がしないです。● 詳しい解説はblogに書こうと思います。
![Page 22: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/22.jpg)
Scalazでのファイル操作
● 入力に関してはbufferFileなどを直接使わずに、Iterateeな関数を使うと良いです。
● getFileLinesは便利。closeは関数内でしている。
● なぜか出力の関数はハブられてる。
● closeWriterぐらいはあってもいいのではないか・・・・
● まだいろいろと足りないイメージ。
![Page 23: Scalaz effects](https://reader034.vdocuments.net/reader034/viewer/2022042714/556f66e0d8b42a9d338b4847/html5/thumbnails/23.jpg)
参考資料など
● Iterateeについて○ Scalaz Tutorial: Enumeration-Based I/O with
Iteratees○ Lazy I/O must go! - Iteratee: 列挙ベースのI/O
● 本
○ Real World Haskellーー実戦で学ぶ関数型言語プログラミング