Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
OptionReader = Kleisli[Option]
case class OptionReader[A, B](run: A => Option[B]) {
def map[C](f: B => C): OptionReader[A, C] =
OptionReader(run(_) map f)
def flatMap[C](f: B => OptionReader[A, C]): OptionReader[A, C] =
OptionReader(a => run(a) flatMap(f(_) run a))
def andThen[C](x: OptionReader[B, C]): OptionReader[A, C] =
OptionReader(run(_) flatMap (x.run(_)))
def compose[C](x: OptionReader[C, A]): OptionReader[C, B] =
x andThen this
def orElse(x: => OptionReader[A, B]): OptionReader[A, B] =
OptionReader(a => run(a) orElse x.run(a))
// alias for orElse
def |||(x: => OptionReader[A, B]): OptionReader[A, B] =
orElse(x)
def zip[C](x: OptionReader[A, C]): OptionReader[A, (B, C)] =
for {
b <- this
c <- x
} yield (b, c)
def product[C, D](x: OptionReader[C, D]): OptionReader[(A, C), (B, D)] =
OptionReader {
case (a, c) =>
for {
b <- run(a)
d <- x run c
} yield (b, d)
}
// alias for product
def ***[C, D](x: OptionReader[C, D]): OptionReader[(A, C), (B, D)] =
product(x)
def first[C]: OptionReader[(A, C), (B, C)] =
OptionReader {
case (a, c) => run(a) map ((_, c))
}
def second[C]: OptionReader[(C, A), (C, B)] =
OptionReader {
case (c, a) => run(a) map ((c, _))
}
def sum[C, D](x: OptionReader[C, D]): OptionReader[A Either C, B Either D] =
OptionReader {
case Left(a) => run(a) map (Left(_))
case Right(c) => x run c map (Right(_))
}
// alias for sum
def +++[C, D](x: OptionReader[C, D]): OptionReader[A Either C, B Either D] =
sum(x)
def left[C]: OptionReader[A Either C, B Either C] =
OptionReader {
case Left(a) => run(a) map (Left(_))
case Right(c) => Some(Right(c))
}
def right[C]: OptionReader[C Either A, C Either B] =
OptionReader {
case Left(c) => Some(Left(c))
case Right(a) => run(a) map (Right(_))
}
def or(b: => B): A => B =
a => run(a) getOrElse b
// alias for or
def |(b: => B): A => B =
or(b)
def too: OptionReader[A, (A, B)] =
OptionReader(a => run(a) map ((a, _)))
}
object OptionReader {
type =?>[A, B] =
OptionReader[A, B]
def identity[A]: OptionReader[A, A] =
OptionReader(a => Some(a))
def lift[A, B](f: A => B): A =?> B =
OptionReader(a => Some(f(a)))
def constant[A, B](b: => B): A =?> B =
lift(_ => b)
def none[A, B]: A =?> B =
OptionReader(_ => None)
def app[A, B]: OptionReader[(OptionReader[A, B], A), B] =
OptionReader {
case (r, a) => r run a
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment