Skip to content

Instantly share code, notes, and snippets.

@halcat0x15a
Created September 4, 2011 19:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save halcat0x15a/1193384 to your computer and use it in GitHub Desktop.
Save halcat0x15a/1193384 to your computer and use it in GitHub Desktop.
ScalazでIteratee
sealed trait StreamG[+E]
case object Empty extends StreamG[Nothing]
case class El[E](el: E) extends StreamG[E]
case object EOF extends StreamG[Nothing]
sealed trait IterV[+E, +A]
case class Done[E, A](x: A, str: StreamG[E]) extends IterV[E, A]
case class Cont[E, A](k: StreamG[E] => IterV[E, A]) extends IterV[E, A]
def enum[E, A]: (IterV[E, A], List[E]) => IterV[E, A] = {
case (i, Nil) => i
case (i@Done(_, _), _) => i
case (Cont(k), x :: xs) => enum(k(El(x)), xs)
}
def run[E, A]: IterV[E, A] => Option[A] = {
case Done(x, _) => Some(x)
case Cont(k) => k(EOF) match {
case Done(x, _) => Some(x)
case _ => None
}
}
def head[E]: IterV[E, Option[E]] = {
def step: StreamG[E] => IterV[E, Option[E]] = {
case El(el) => Done(Some(el), Empty)
case Empty => Cont(step)
case EOF => Done(None, EOF)
}
Cont(step)
}
def peek[E]: IterV[E, Option[E]] = {
def step: StreamG[E] => IterV[E, Option[E]] = {
case c@El(el) => Done(Some(el), c)
case Empty => Cont(step)
case EOF => Done(None, EOF)
}
Cont(step)
}
def drop[E]: Int => IterV[E, Unit] = {
case 0 => Done((), Empty)
case n => {
def step: StreamG[E] => IterV[E, Unit] = {
case El(_) => drop(n - 1)
case Empty => Cont(step)
case EOF => Done((), EOF)
}
Cont(step)
}
}
def length[E]: IterV[E, Int] = {
def step: (Int, StreamG[E]) => IterV[E, Int] = {
case (acc, El(_)) => Cont(step.curried(acc + 1))
case (acc, Empty) => Cont(step.curried(acc))
case (acc, EOF) => Done(acc, EOF)
}
Cont(step.curried(0))
}
implicit def IterVMonad[E] = new Monad[({type X[A] = IterV[E, A]})#X] {
def pure[A](x: => A): IterV[E, A] = Done(x, Empty)
def bind[A, B](m: IterV[E, A], f: A => IterV[E, B]): IterV[E, B] = m match {
case Done(x, str) => f(x) match {
case Done(x, _) => Done(x, str)
case Cont(k) => k(str)
}
case Cont(k) => Cont((str: StreamG[E]) => bind(k(str), f))
}
}
def f[E](l: List[E]) = run(enum(drop(2) >|> length, l))
f(List(1, 2, 3)) assert_=== Some(1)
f(List(1, 2, 3, 4, 5)) assert_=== Some(3)
f(List(1)) assert_=== Some(0)
type EnumeratorM[E, M[_], A] = IterV[E, A] => M[IterV[E, A]]
def enumReader[A](r: BufferedReader): EnumeratorM[String, IO, A] = { iter =>
def loop: EnumeratorM[String, IO, A] = {
case i @ Done(_, _) => (i: IterV[String, A]).pure[IO]
case i @ Cont(k) => for {
o <- rReadLn(r)
i <- o match {
case None => i.pure[IO]
case Some(s) => s.pure[IO] >>= loop.compose(k.compose(El(_)))
}
} yield i
}
loop(iter)
}
def enumFile[A](f: File): EnumeratorM[String, IO, A] = i => bufferFile(f).bracket(closeReader)(enumReader[A](_)(i))
val file = new File("src/main/resources/test.txt")
file.exists assert_=== true
def g[A](i: IterV[String, A]) = run(enumFile(file)(i).unsafePerformIO)
g(length) assert_=== Some(1)
g(peek[String] >|> head[String]) assert_=== Some(Some("hello"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment