public
Last active

DerivingApplicative

  • Download Gist
deriving-applicative.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
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

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.