Created
September 18, 2010 12:45
-
-
Save retronym/585629 to your computer and use it in GitHub Desktop.
DerivingApplicative
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
object DerivingApplicative extends Application { | |
val o1: Option[Int] = Some(1) | |
val o2: Option[Int] = Some(2) | |
val s1 = Stream from 1 | |
val s2 = Stream(0, 1) | |
object Take1 { | |
def tupleOptions[A, B](a: Option[A], b: Option[B]): Option[(A, B)] = | |
(a, b) match { | |
case (Some(a), Some(b)) => Some((a, b)) | |
case _ => None | |
} | |
def tupleStreams[A, B](a: Stream[A], b: Stream[B]): Stream[(A, B)] = | |
if (a.isEmpty || b.isEmpty) Stream.empty | |
else Stream.cons((a.head, b.head), tupleStreams(a.tail, b.tail)) | |
assert(tupleOptions(o1, o2) == Some(1, 2)) | |
assert(tupleStreams(s1, s2) == Stream((1, 0), (2, 1))) | |
} | |
object Take2 { | |
def combineOptionsWith[A, B, C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] = | |
(a, b) match { | |
case (Some(a), Some(b)) => Some(f(a, b)) | |
case _ => None | |
} | |
def combineStreamsWith[A, B, C](a: Stream[A], b: Stream[B])(f: (A, B) => C): Stream[C] = | |
if (a.isEmpty || b.isEmpty) Stream.empty | |
else Stream.cons(f(a.head, b.head), combineStreamsWith(a.tail, b.tail)(f)) | |
def tupleOptions[A, B](a: Option[A], b: Option[B]): Option[(A, B)] = | |
combineOptionsWith(a, b)(Tuple2.apply) | |
def tupleStreams[A, B](a: Stream[A], b: Stream[B]): Stream[(A, B)] = | |
combineStreamsWith(a, b)(Tuple2.apply) | |
assert(tupleOptions(o1, o2) == Some(1, 2)) | |
assert(tupleStreams(s1, s2) == Stream((1, 0), (2, 1))) | |
} | |
object Take3 { | |
trait Apply[F[_]] { | |
def apply[A, B, C](a: F[A], b: F[B], f: (A, B) => C): F[C] | |
} | |
object Apply { | |
implicit val OptionApply: Apply[Option] = new Apply[Option] { | |
def apply[A, B, C](a: Option[A], b: Option[B], f: (A, B) => C) = (a, b) match { | |
case (Some(a), Some(b)) => Some(f(a, b)) | |
case _ => None | |
} | |
} | |
implicit val StreamApply: Apply[Stream] = new Apply[Stream] { | |
def apply[A, B, C](a: Stream[A], b: Stream[B], f: (A, B) => C): Stream[C] = | |
if (a.isEmpty || b.isEmpty) Stream.empty | |
else Stream.cons(f(a.head, b.head), apply(a.tail, b.tail, f)) | |
} | |
} | |
def tupleF[F[_], A, B](a: F[A], b: F[B])(implicit ap: Apply[F]): F[(A, B)] = | |
ap.apply(a, b, Tuple2.apply[A, B]) | |
assert(tupleF(o1, o2) == Some(1, 2)) | |
assert(tupleF(s1, s2) == Stream((1, 0), (2, 1))) | |
} | |
object Take4 { | |
trait Applicative[F[_]] { | |
def pure[A](a: => A): F[A] | |
def apply[A, B](fab: F[A => B], fa: F[A]): F[B] | |
def fmap[A, B](fa: F[A], f: A => B): F[B] = apply(pure(f), fa) | |
def apply[A, B, C](fa: F[A], fb: F[B], f: (A, B) => C): F[C] = { | |
val fbc: F[B => C] = fmap(fa, (a: A) => (b: B) => f(a, b)) | |
apply(fbc, fb) | |
} | |
} | |
object Applicative { | |
implicit val OptionApplicative: Applicative[Option] = new Applicative[Option] { | |
def pure[A](a: => A) = Some(a) | |
def apply[A, B](fab: Option[(A) => B], fa: Option[A]) = (fab, fa) match { | |
case (Some(f), Some(a)) => Some(f(a)) | |
case _ => None | |
} | |
} | |
implicit val StreamApplicative: Applicative[Stream] = new Applicative[Stream] { | |
def pure[A](a: => A) = Stream.continually(a) | |
def apply[A, B](fab: scala.Stream[(A) => B], fa: scala.Stream[A]) = | |
if (fab.isEmpty || fa.isEmpty) Stream.empty | |
else Stream.cons(fab.head(fa.head), apply(fab.tail, fa.tail)) | |
} | |
} | |
def genericCombine[F[_], A, B](a: F[A], b: F[B])(implicit ap: Applicative[F]): F[(A, B)] = | |
ap.apply(a, b, Tuple2.apply[A, B]) | |
assert(genericCombine(o1, o2) == Some(1, 2)) | |
assert(genericCombine(s1, s2) == Stream((1, 0), (2, 1))) | |
} | |
object Take5 { | |
trait Applicative[F[_]] { | |
def pure[A](a: => A): F[A] | |
def apply[A, B](fab: F[A => B], fa: F[A]): F[B] | |
def fmap[A, B](fa: F[A], f: A => B): F[B] = apply(pure(f), fa) | |
} | |
object Applicative { | |
implicit val OptionApplicative: Applicative[Option] = new Applicative[Option] { | |
def pure[A](a: => A) = Some(a) | |
def apply[A, B](fab: Option[(A) => B], fa: Option[A]) = (fab, fa) match { | |
case (Some(f), Some(a)) => Some(f(a)) | |
case _ => None | |
} | |
} | |
implicit val StreamApplicative: Applicative[Stream] = new Applicative[Stream] { | |
def pure[A](a: => A) = Stream.continually(a) | |
def apply[A, B](fab: scala.Stream[(A) => B], fa: scala.Stream[A]) = | |
if (fab.isEmpty || fa.isEmpty) Stream.empty | |
else Stream.cons(fab.head(fa.head), apply(fab.tail, fa.tail)) | |
} | |
} | |
case class MA[M[_], A](value: M[A]) { | |
def <|*|>[B](mb: M[B])(implicit ap: Applicative[M]): M[(A, B)] = { | |
val mbc: M[B => (A, B)] = ap.fmap(value, (a: A) => (b: B) => (a, b)) | |
ap.apply(mbc, mb) | |
} | |
} | |
implicit def ma[M[_], A](ma: M[A]): MA[M, A] = MA(ma) | |
assert(o1.<|*|>(o2) == Some((1, 2))) | |
} | |
Take1 | |
Take2 | |
Take3 | |
Take4 | |
Take5 | |
} | |
DerivingApplicative |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment