2012年9月10日月曜日

Scalaでdo記法

函数プログラミングの集いで限定継続の話が面白かったので書いておきます。

ScalaでもHaskellのdo記法っぽく書ける。

調度良くScalaでHaskellしてる記事があったので、これを参考にさせていただきます。

import scala.language._
import scala.util.continuations._
import scalaz._, Scalaz._
import effect._, IO._
import scalaz.syntax.Ops
object Do {
sealed trait DoBindOps[F[_], A] extends Ops[F[A]] {
implicit val F: Bind[F]
val self: F[A]
def bind[B] = shift((k: A => F[B]) => self >>= k)
}
implicit def ToDoBindOps[F[_]: Bind, A](fa: F[A]) = new DoBindOps[F, A] {
val F = implicitly[Bind[F]]
val self = fa
}
def apply[F[_]: Bind, A](fa: => F[A] @cps[F[A]]) = reset(fa)
}
object Main extends SafeApp {
import Do._
override def runc = Do {
ch07.basicio.bind[Unit]
ch07.callingpure
}
object ch07 {
def basicio = Do {
putStrLn("Greetings! What is your name?").bind[Unit]
val inpStr = readLn.bind[Unit]
putStrLn(s"Welcome to Haskell, $inpStr!")
}
def callingpure = {
def name2reply(name: String) = {
val charcount = name.length
s"""Pleased to meet you, $name.
Your name contains $charcount characters."""
}
Do {
putStrLn("Greetings once again. What is your name?").bind[Unit]
val inpStr = readLn.bind[Unit]
val outStr = name2reply(inpStr)
putStrLn(outStr)
}
}
}
}
view raw gistfile1.scala hosted with ❤ by GitHub
\めんどい/

※追記

実践Scalaプログラミング読みなおしてみたらこっちの方が良さそう。

import scala.language._
import scala.util.continuations._
import scalaz.syntax.bind._
import scalaz.effect._, IO._
class Do[A] {
class Bind[B] {
def apply[F[_]: scalaz.Bind, A](fa: F[A]) = shift((k: A => F[B]) => fa >>= k)
}
def apply[F[_]](f: Bind[A] => F[A] @cps[F[A]]) = reset(f(new Bind[A]))
}
object Do {
def apply[A] = new Do[A]
}
object Main extends SafeApp {
override def runc = Do[Unit] { bind =>
bind(ch07.basicio)
ch07.callingpure
}
object ch07 {
def basicio = Do[Unit] { bind =>
bind(putStrLn("Greetings! What is your name?"))
val inpStr = bind(readLn)
putStrLn(s"Welcome to Haskell, $inpStr!")
}
def callingpure = {
def name2reply(name: String) = {
val charcount = name.length
s"""Pleased to meet you, $name.
Your name contains $charcount characters."""
}
Do[Unit] { bind =>
bind(putStrLn("Greetings once again. What is your name?"))
val inpStr = bind(readLn)
val outStr = name2reply(inpStr)
putStrLn(outStr)
}
}
}
}
view raw gistfile1.scala hosted with ❤ by GitHub

しかし、完全に推論させることは出来なさそう。

for式使いましょう。

0 件のコメント:

コメントを投稿