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