Skip to content

Instantly share code, notes, and snippets.

@shajra
Last active August 29, 2015 14:09
Show Gist options
  • Save shajra/39cdc9c08546d334029a to your computer and use it in GitHub Desktop.
Save shajra/39cdc9c08546d334029a to your computer and use it in GitHub Desktop.
an idea for error handling in scalaz-stream
package myorg.extn.scalaz
import scala.Unit
import scalaz.{ \/, EitherT, Functor, Maybe }
import scalaz.EitherT.eitherT
import scalaz.stream.{ Process, Cause }
import scalaz.stream.Process.
{ emit, emitO, emitW, eval, eval_, fail, halt, repeatEval }
import scalaz.syntax.bind._
/** Extension of Scalaz-stream library */
package object stream {
object io {
def resource[F[_] : Functor, R, O]
(acquire: F[R])
(release: R => F[Unit])
(step: R => F[Maybe[O]])
: Process[F,O] = {
type P[A] = Process[F, A]
val getResource: P[R] = eval(acquire)
def repeat(r: R): P[O] =
repeatEval(step(r)) >>= { _.map[P[O]](emit) | end[F, O] }
def repeatAndClose(r: R): P[O] =
repeat(r).onComplete[F, O](eval_(release(r)))
getResource >>= repeatAndClose
}
def resourceE[F[_] : Functor, R, E, O]
(acquire: F[E \/ R])
(release: R => F[Unit])
(step: R => F[Result[E, O]])
: Process[F, E \/ O] = {
type P[A] = Process[F, A]
type EP[A] = EitherT[P, E, A]
val getResource: EP[R] =
eitherT[P, E, R](eval(acquire))
def repeat(r: R): P[E \/ O] =
repeatEval(step(r)) >>=
{ res =>
res fold[P[E \/ O]] (
cont = emitO(_),
done = end[F, E \/ O],
failCont = emitW(_),
failStop = emitW(_) ++ (end[F, E \/ O]))
}
def repeatAndClose(r: R): EP[O] =
eitherT[P, E, O](repeat(r).onComplete[F, E \/ O](eval_(release(r))))
getResource >>= repeatAndClose run
}
private def end[F[_], A]: Process[F, A] = {
//halt // this doesn't work
fail(Cause.Terminated(Cause.End)) // this works, but why?
}
}
}
package myorg.extn.scalaz.stream
sealed abstract class Result[E, O] {
def fold[A]
(cont: O => A, done: => A, failCont: E => A, failStop: E => A) =
this match {
case Cont(o) => cont(o)
case Done() => done
case FailCont(e) => failCont(e)
case FailStop(e) => failStop(e)
}
}
private case class Cont[E, O](o: O) extends Result[E, O]
private case class Done[E, O]() extends Result[E, O]
private case class FailCont[E, O](e: E) extends Result[E, O]
private case class FailStop[E, O](e: E) extends Result[E, O]
object Result {
def cont[E, O](o: O): Result[E, O] = Cont(o)
def done[E, O](): Result[E, O] = Done()
def failCont[E, O](e: E): Result[E, O] = FailCont(e)
def failStop[E, O](e: E): Result[E, O] = FailStop(e)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment