Skip to content

Instantly share code, notes, and snippets.

@halcat0x15a
Created September 3, 2011 14:00
Show Gist options
  • Save halcat0x15a/1191224 to your computer and use it in GitHub Desktop.
Save halcat0x15a/1191224 to your computer and use it in GitHub Desktop.
ScalazでIteratee
sealed trait StreamG[+E]
case class Empty[E]() extends StreamG[E]
case class El[E](el: E) extends StreamG[E]
case class EOF[E]() extends StreamG[E]
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: A, _) => Some(x)
case Cont(k) => k(EOF()) match {
case Done(x: A, _) => Some(x)
case _ => None
}
}
def head[E]: IterV[E, Option[E]] = {
def step: StreamG[E] => IterV[E, Option[E]] = {
case El(el: E) => 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: E) => 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: A, str: StreamG[E]) => f(x) match {
case Done(x: B, _) => 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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment