package io.catbird.util import cats.{ CoflatMap, Comonad, Eq, Monad, Monoid, Semigroup } import com.twitter.util.Var import scala.Boolean import scala.util.{ Either, Left, Right } trait VarInstances extends VarInstances1 { implicit final val twitterVarInstance: Monad[Var] with CoflatMap[Var] = new VarCoflatMap with Monad[Var] { final def pure[A](x: A): Var[A] = Var.value(x) final def flatMap[A, B](fa: Var[A])(f: A => Var[B]): Var[B] = fa.flatMap(f) override final def map[A, B](fa: Var[A])(f: A => B): Var[B] = fa.map(f) } implicit final def twitterVarSemigroup[A](implicit A: Semigroup[A]): Semigroup[Var[A]] = new VarSemigroup[A] final def varEq[A](implicit A: Eq[A]): Eq[Var[A]] = new Eq[Var[A]] { final def eqv(fx: Var[A], fy: Var[A]): Boolean = Var.sample( fx.join(fy).map { case (x, y) => A.eqv(x, y) } ) } } trait VarInstances1 { final def varComonad: Comonad[Var] = new VarCoflatMap with Comonad[Var] { final def extract[A](x: Var[A]): A = Var.sample(x) final def map[A, B](fa: Var[A])(f: A => B): Var[B] = fa.map(f) } implicit final def twitterVarMonoid[A](implicit A: Monoid[A]): Monoid[Var[A]] = new VarSemigroup[A] with Monoid[Var[A]] { final def empty: Var[A] = Var.value(A.empty) } } private[util] abstract class VarCoflatMap extends CoflatMap[Var] { final def coflatMap[A, B](fa: Var[A])(f: Var[A] => B): Var[B] = Var(f(fa)) /** * Note that this implementation is not stack-safe. */ final def tailRecM[A, B](a: A)(f: A => Var[Either[A, B]]): Var[B] = f(a).flatMap { case Left(a1) => tailRecM(a1)(f) case Right(b) => Var.value(b) } } private[util] class VarSemigroup[A](implicit A: Semigroup[A]) extends Semigroup[Var[A]] { final def combine(fx: Var[A], fy: Var[A]): Var[A] = fx.join(fy).map { case (x, y) => A.combine(x, y) } }