Created
July 31, 2013 10:09
-
-
Save nafg/6120889 to your computer and use it in GitHub Desktop.
two way iteratee based on jsuereth and others
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package chavrusa.ivr | |
import Trampoline.{ Done => TDone, More => TMore, Cont => TCont } | |
trait Iteratees[Err] { | |
sealed trait Input[+I] | |
case class El[+I](value: I) extends Input[I] | |
case object Empty extends Input[Nothing] | |
case object EOF extends Input[Nothing] | |
sealed trait Step[I, A] | |
case class Cont[I, A](data: Option[Err], k: Input[I] => Iteratee[I, A]) extends Step[I, A] | |
case class Done[I, A](result: A, remaining: Input[I]) extends Step[I, A] | |
case class Error[I, A](err: Err, resume: Input[I]) extends Step[I, A] | |
type Identity[A] = A | |
trait Iteratee[I, O] { | |
def fold[A, F[_]](f: Step[I, O] => F[A]): F[A] | |
def flatMap[P](next: O => Iteratee[I, P]): Iteratee[I, P] = this.fold[Iteratee[I, P], Trampoline]{ | |
case Done(a, remaining) => | |
TMore{() => | |
println(s"got Done($a, $remaining)") | |
TDone(next(a).fold[Iteratee[I, P], Identity] { | |
case Cont(_, k) => | |
println("next(a) was a Cont(k), remaining = " + remaining) | |
k(remaining) | |
case other => Iteratee(other) | |
})} | |
case Error(e, r) => TDone(Iteratee(Error[I, P](e, r))) | |
case Cont(d, k) => TMore{ () => | |
TDone(Iteratee(Cont(d, (in: Input[I]) => k(in) flatMap next))) | |
} | |
}.run | |
def zip[P](that: Iteratee[I, P]) = new ZippedIteratee(this, that) | |
def run: Either[Err, O] = { | |
def loop(it: Iteratee[I, O]): Trampoline[Either[Err, O]] = it fold { | |
case Cont(d, k) => loop(k(EOF)) | |
case Done(a, _) => TDone(Right(a)) | |
case Error(err, _) => TDone(Left(err)) | |
} | |
loop(this).run | |
} | |
} | |
case class SimpleIteratee[I, O](step: Step[I, O]) extends Iteratee[I, O] { | |
def fold[A, F[_]](f: Step[I, O] => F[A]) = f(step) | |
} | |
object Iteratee { | |
def apply[I, O](s: Step[I, O]) = SimpleIteratee(s) | |
} | |
class ZippedIteratee[I, A, B](a: Iteratee[I, A], b: Iteratee[I, B]) extends Iteratee[I, (A, B)] { | |
private def drive(i: Input[I]): Iteratee[I, (A, B)] = | |
new ZippedIteratee(Enumerator.once(i) apply a, Enumerator.once(i) apply b) | |
def fold[R, F[_]](f: Step[I, (A, B)] => F[R]): F[R] = a fold { sa => | |
b fold { sb => | |
(sa, sb) match { | |
case (Done(a, i), Done(b, _)) => f(Done((a, b), i)) | |
case (Error(e, res), _) => f(Error(e, res)) | |
case (_, Error(e, res)) => f(Error(e, res)) | |
case (Cont(msg, _), _) => f(Cont(msg, drive)) | |
case (_, Cont(msg, _)) => f(Cont(msg, drive)) | |
case _ => f(Cont(None, drive)) | |
} | |
} | |
} | |
} | |
trait Enumerator[I] { outer => | |
def apply[O](input: Iteratee[I, O]): Iteratee[I, O] | |
// def convert[J](f: Enumeratee[I, J]): Enumerator[J] = new Enumerator[J] { | |
// def apply[O](c: Iteratee[J, O]): Iteratee[J, O] = { | |
// def step(x: Iteratee[I, Iteratee[J, O]]): Trampoline[Iteratee[J, O]] = x fold { | |
// case Done(a, i) => TDone(a) | |
// case Error(e, res) => TDone(Iteratee(Error(e, EOF))) // FIXME resume=? | |
// case Cont(d, k) => TMore{ () => | |
// step(k(Empty)) //FIXME this can't be right... | |
// } | |
// } | |
// step(outer apply (f apply c)).run | |
// } | |
// } | |
} | |
object Enumerator { | |
def once[I](value: Input[I]): Enumerator[I] = new Enumerator[I] { | |
def apply[O](input: Iteratee[I, O]) = (input.fold[Iteratee[I, O], Identity] { | |
case Cont(_, k) => k(value) | |
case other => Iteratee(other) | |
}) | |
} | |
/*def list[E](xs: List[E]): Enumerator[E] = { | |
def loop[A](xs: List[E], iteratee: Iteratee[E, A]): Trampoline[Iteratee[E, A]] = xs match { | |
case Nil => TDone(iteratee) | |
case x :: xs => iteratee fold { | |
case Cont(k) => TMore(() => loop(xs, k(El(x)))) | |
case _ => TDone(iteratee) | |
} | |
} | |
new Enumerator[E] { | |
def apply[A](iteratee: Iteratee[E, A]) = loop(xs, iteratee).run | |
} | |
}*/ | |
} | |
trait Enumeratee[I, J] { | |
def apply[O](i: Iteratee[J, O]): Iteratee[I, Iteratee[J, O]] | |
def convert[O](i: Iteratee[J, O]): Iteratee[I, O] = ??? | |
} | |
def counter[I]: Iteratee[I, Long] = { | |
def step(n: Long): Input[I] => Iteratee[I, Long] = { | |
case El(x) => Iteratee(Cont(None, step(n + 1))) | |
case Empty => Iteratee(Cont(None, step(n))) | |
case EOF => Iteratee(Done(n, EOF)) | |
} | |
Iteratee(Cont(None, step(0))) | |
} | |
def consume(data: Seq[Int] = Nil): Iteratee[Int, Seq[Int]] = Iteratee(Cont(None, { | |
case El(byte) => consume(data :+ byte) | |
case Empty => consume(data) | |
case EOF => Iteratee(Done(data, EOF)) | |
})) | |
} | |
object Iteratees extends Iteratees[String] { | |
def peek[I]: Iteratee[I, Option[I]] = Iteratee(Cont(None, { | |
case El(i) => Iteratee(Done(Some(i), El(i))) | |
case EOF => Iteratee(Done(None, Empty)) | |
case Empty => peek | |
})) | |
def head[I]: Iteratee[I, Option[I]] = Iteratee(Cont(None, { | |
case El(i) => Iteratee(Done(Some(i), Empty)) | |
case EOF => Iteratee(Done(None, Empty)) | |
case Empty => head | |
})) | |
} | |
object TestIteratees extends Iteratees[String] with App { | |
trait Enumerator[I] extends super.Enumerator[I] { | |
} | |
def consume2(data: Seq[Int] = Nil): Iteratee[Int, Seq[Int]] = Iteratee(Cont(None, { | |
case El(byte) => consume(data :+ byte) | |
case Empty => consume(data) | |
case EOF => Iteratee(Done(data, EOF)) | |
})) | |
def echoIteratee: Iteratee[String, String] = { | |
def handler: Input[String] => Iteratee[String, String] = { | |
case El("quit") => Iteratee(Done("Goodbye", EOF)) | |
case El(s) => Iteratee(Cont(Some(s"You said: '$s'"), handler)) | |
case Empty => echoIteratee | |
case EOF => Iteratee(Error("The end", EOF)) | |
} | |
Iteratee(Cont[String, String](Some("Please enter some text"), handler)) | |
} | |
// def repeat: Iteratee[String, String] = echoIteratee flatMap { _ => repeat } | |
def enumerateIt(it: Iteratee[String, String]): IO[Iteratee[String, String]] = { | |
def loop: Iteratee[String, String] => IO[Iteratee[String, String]] = _ fold { | |
case d @ Done(s, next) => for { | |
_ <- IO { println(s) } | |
i <- IO { it } | |
} yield i | |
case Cont(d, k) => | |
IO{ d foreach println } flatMap { _ => | |
IO{ Console.readLine } flatMap { s => | |
if(s == null) IO { Iteratee(Done("", EOF)) } | |
else loop(k(El(s))) | |
} | |
} | |
case Error(msg, resume) => | |
println("Got error: "+msg ) | |
IO { Iteratee(Done(msg, resume)) } | |
} | |
loop(it) | |
} | |
// def repeat: Trampoline[Iteratee[String, String]] = TDone(echoIteratee) flatMap (_ => repeat) | |
enumerateIt(echoIteratee).unsafePerformIO.run | |
// def inputs[E]: Enumerator[E] = { | |
// def loop[A](xs: List[E], iteratee: Iteratee[E, A]): Trampoline[Iteratee[E, A]] = xs match { | |
// case Nil => TDone(iteratee) | |
// case x :: xs => iteratee fold { | |
// case Cont(k) => TMore(() => loop(xs, k(El(x)))) | |
// case _ => TDone(iteratee) | |
// } | |
// } | |
// new Enumerator[E] { | |
// def apply[A](iteratee: Iteratee[E, A]) = loop(xs, iteratee).run | |
// } | |
// } | |
} | |
object IvrIteratees extends Iteratees[Sayable] { | |
/*def sillyIteratee: Iteratee[Char, Sayable] = Iteratee(Cont{ | |
case El(c) => Done(ChavrusaSayables.digitWords(c.toString)(null), EOF) | |
case Empty => sillyIteratee | |
case EOF => | |
})*/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment