Skip to content

Instantly share code, notes, and snippets.

@retronym
Created September 18, 2010 12:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save retronym/585629 to your computer and use it in GitHub Desktop.
Save retronym/585629 to your computer and use it in GitHub Desktop.
DerivingApplicative
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