-
-
Save rossabaker/503c28ef1cb2492f2db656084b11a16a to your computer and use it in GitHub Desktop.
This file contains 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 org.http4s | |
import cats._ | |
import cats.mtl._ | |
final class Service[F[_], -A, B] private (private[Service] val run: A => F[B]) { | |
def seal[B2 >: B](default: B2)(implicit F: Functor[F]): A => F[B2] = | |
a => F.map(run(a)) { | |
case null => default | |
case b => b | |
} | |
def lifted(implicit F: Functor[F]): A => F[Option[B]] = | |
a => F.map(run(a)) { | |
case null => None | |
case b => Some(b) | |
} | |
def map[C](f: B => C)(implicit F: Functor[F]): Service[F, A, C] = | |
new Service(a => F.map(run(a)) { | |
case null => null.asInstanceOf[C] | |
case b => f(b) | |
}) | |
def flatMap[AA <: A, C](f: B => Service[F, AA, C])(implicit F: FlatMap[F]): Service[F, AA, C] = | |
new Service(a => F.flatMap(run(a)) { | |
case null => null.asInstanceOf[F[C]] | |
case b => f(b).run(a) | |
}) | |
def local[C](f: C => A): Service[F, C, B] = | |
new Service(c => run(f(c))) | |
def orElse[AA <: A](that: Service[F, AA, B])(implicit F: Monad[F]): Service[F, AA, B] = | |
new Service(a => F.flatMap(run(a)) { | |
case null => that.run(a) | |
case b => F.pure(b) | |
}) | |
} | |
object Service { | |
def pure[F[_], A, B](b: B)(implicit F: Applicative[F]): Service[F, A, B] = | |
new Service(Function.const(F.pure(b))) | |
def of[F[_], A, B](pf: PartialFunction[A, F[B]])(implicit F: Applicative[F]) = | |
new Service((a: A) => pf.applyOrElse(a, Function.const(F.pure(null.asInstanceOf[B])))) | |
implicit def monad[F[_], A](implicit F: Monad[F]) = | |
new Monad[Service[F, A, *]] { | |
def pure[B](b: B): Service[F, A, B] = | |
Service.pure[F, A, B](b) | |
def flatMap[B, C](fb: Service[F, A, B])(f: B => Service[F, A, C]) = | |
fb.flatMap(f) | |
def tailRecM[B, C](b: B)(f: B => Service[F, A, Either[B, C]]) = | |
??? | |
} | |
implicit def monoidK[F[_], A](implicit F: Monad[F], FK: MonoidK[F]) = | |
new MonoidK[Service[F, A, *]] { | |
def combineK[B](x: Service[F, A, B], y: Service[F, A, B]) = | |
new Service(a => F.flatMap(x.run(a)) { | |
case null => y.run(a) | |
case b => F.pure(b) | |
}) | |
def empty[B] = | |
new Service(Function.const(FK.empty)) | |
} | |
// TODO only needs Applicative | |
implicit def local[F[_], A](implicit F: Monad[F]): Local[Service[F, A, *], A] = | |
new Local[Service[F, A, *], A] { | |
def applicative = | |
monad[F, A] | |
def ask[A2 >: A] = | |
new Service(F.pure) | |
def local[B](fb: Service[F, A, B])(f: A => A) = | |
fb.local(f) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment