Skip to content

Commit 83dd631

Browse files
committed
Implement several Functor methods to avoid using map when not needed
1 parent e94ddf0 commit 83dd631

File tree

9 files changed

+112
-0
lines changed

9 files changed

+112
-0
lines changed

core/src/main/scala/cats/instances/either.scala

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,36 @@ trait EitherInstances extends cats.kernel.instances.EitherInstances {
7777
override def map[B, C](fa: Either[A, B])(f: B => C): Either[A, C] =
7878
fa.map(f)
7979

80+
override def as[B, C](fa: Either[A, B], c: C): Either[A, C] =
81+
fa match {
82+
case Right(_) => Right(c)
83+
case left @ Left(_) => left.rightCast[C]
84+
}
85+
86+
override def tupleLeft[B, C](fa: Either[A, B], c: C): Either[A, (C, B)] =
87+
fa match {
88+
case Right(b) => Right((c, b))
89+
case left @ Left(_) => left.rightCast[(C, B)]
90+
}
91+
92+
override def tupleRight[B, C](fa: Either[A, B], c: C): Either[A, (B, C)] =
93+
fa match {
94+
case Right(b) => Right((b, c))
95+
case left @ Left(_) => left.rightCast[(B, C)]
96+
}
97+
98+
override def fproduct[B, C](fa: Either[A, B])(f: B => C): Either[A, (B, C)] =
99+
fa match {
100+
case Right(b) => Right((b, f(b)))
101+
case left @ Left(_) => left.rightCast[(B, C)]
102+
}
103+
104+
override def fproductLeft[B, C](fa: Either[A, B])(f: B => C): Either[A, (C, B)] =
105+
fa match {
106+
case Right(b) => Right((f(b), b))
107+
case left @ Left(_) => left.rightCast[(C, B)]
108+
}
109+
80110
@tailrec
81111
def tailRecM[B, C](b: B)(f: B => Either[A, Either[B, C]]): Either[A, C] =
82112
f(b) match {
@@ -210,6 +240,12 @@ trait EitherInstances extends cats.kernel.instances.EitherInstances {
210240
}
211241
}
212242

243+
override def unzip[B, C](fab: Either[A, (B, C)]): (Either[A, B], Either[A, C]) =
244+
fab match {
245+
case Right((b, c)) => (Right(b), Right(c))
246+
case left @ Left(_) => (left.rightCast[B], left.rightCast[C])
247+
}
248+
213249
override def void[B](e: Either[A, B]): Either[A, Unit] =
214250
if (e.isRight) Either.unit
215251
else e.asInstanceOf[Either[A, Unit]] // it is Left(a)

core/src/main/scala/cats/instances/list.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ trait ListInstances extends cats.kernel.instances.ListInstances {
203203
override def zipWithIndex[A](fa: List[A]): List[(A, Int)] =
204204
fa.zipWithIndex
205205

206+
override def unzip[A, B](fab: List[(A, B)]): (List[A], List[B]) =
207+
fab.unzip
208+
206209
override def partitionEither[A, B, C](
207210
fa: List[A]
208211
)(f: A => Either[B, C])(implicit A: Alternative[List]): (List[B], List[C]) =

core/src/main/scala/cats/instances/map.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ trait MapInstances extends cats.kernel.instances.MapInstances {
5959
override def map[A, B](fa: Map[K, A])(f: A => B): Map[K, B] =
6060
fa.map { case (k, a) => (k, f(a)) }
6161

62+
override def unzip[A, B](fab: Map[K, (A, B)]): (Map[K, A], Map[K, B]) = {
63+
val leftBuilder = Map.newBuilder[K, A]
64+
val rightBuilder = Map.newBuilder[K, B]
65+
leftBuilder.sizeHint(fab.size)
66+
rightBuilder.sizeHint(fab.size)
67+
fab.foreach { case (k, (a, b)) =>
68+
leftBuilder += k -> a
69+
rightBuilder += k -> b
70+
}
71+
(leftBuilder.result(), rightBuilder.result())
72+
}
73+
6274
override def map2[A, B, Z](fa: Map[K, A], fb: Map[K, B])(f: (A, B) => Z): Map[K, Z] =
6375
if (fb.isEmpty) Map.empty // do O(1) work if fb is empty
6476
else fa.flatMap { case (k, a) => fb.get(k).map(b => (k, f(a, b))) }

core/src/main/scala/cats/instances/option.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,33 @@ trait OptionInstances extends cats.kernel.instances.OptionInstances {
7777
override def map[A, B](fa: Option[A])(f: A => B): Option[B] =
7878
fa.map(f)
7979

80+
override def as[A, B](fa: Option[A], b: B): Option[B] =
81+
if (fa.isDefined) Some(b) else None
82+
83+
override def tupleLeft[A, B](fa: Option[A], b: B): Option[(B, A)] =
84+
fa match {
85+
case Some(a) => Some((b, a))
86+
case None => None
87+
}
88+
89+
override def tupleRight[A, B](fa: Option[A], b: B): Option[(A, B)] =
90+
fa match {
91+
case Some(a) => Some((a, b))
92+
case None => None
93+
}
94+
95+
override def fproduct[A, B](fa: Option[A])(f: A => B): Option[(A, B)] =
96+
fa match {
97+
case Some(a) => Some((a, f(a)))
98+
case None => None
99+
}
100+
101+
override def fproductLeft[A, B](fa: Option[A])(f: A => B): Option[(B, A)] =
102+
fa match {
103+
case Some(a) => Some((f(a), a))
104+
case None => None
105+
}
106+
80107
def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] =
81108
fa.flatMap(f)
82109

@@ -244,6 +271,12 @@ trait OptionInstances extends cats.kernel.instances.OptionInstances {
244271
case (Some(a), Some(b)) => Some(f(Ior.both(a, b)))
245272
}
246273

274+
override def unzip[A, B](fab: Option[(A, B)]): (Option[A], Option[B]) =
275+
fab match {
276+
case Some((a, b)) => (Some(a), Some(b))
277+
case None => (None, None)
278+
}
279+
247280
override def unit: Option[Unit] = someUnit
248281
override def void[A](oa: Option[A]): Option[Unit] =
249282
if (oa.isDefined) someUnit else None

core/src/main/scala/cats/instances/queue.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ trait QueueInstances extends cats.kernel.instances.QueueInstances {
189189

190190
override def toIterable[A](fa: Queue[A]): Iterable[A] = fa
191191

192+
override def unzip[A, B](fab: Queue[(A, B)]): (Queue[A], Queue[B]) =
193+
fab.unzip
194+
192195
override def reduceLeftOption[A](fa: Queue[A])(f: (A, A) => A): Option[A] =
193196
fa.reduceLeftOption(f)
194197

core/src/main/scala/cats/instances/seq.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ trait SeqInstances extends cats.kernel.instances.SeqInstances {
150150
override def zipWithIndex[A](fa: Seq[A]): Seq[(A, Int)] =
151151
fa.zipWithIndex
152152

153+
override def unzip[A, B](fab: Seq[(A, B)]): (Seq[A], Seq[B]) =
154+
fab.unzip
155+
153156
override def exists[A](fa: Seq[A])(p: A => Boolean): Boolean =
154157
fa.exists(p)
155158

core/src/main/scala/cats/instances/sortedMap.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ trait SortedMapInstances extends SortedMapInstances2 {
7878
fa.map { case (k, a) => (k, f(a)) }
7979
}
8080

81+
override def unzip[A, B](fab: SortedMap[K, (A, B)]): (SortedMap[K, A], SortedMap[K, B]) = {
82+
implicit val ordering: Ordering[K] = fab.ordering
83+
val leftBuilder = SortedMap.newBuilder[K, A](ordering)
84+
val rightBuilder = SortedMap.newBuilder[K, B](ordering)
85+
leftBuilder.sizeHint(fab.size)
86+
rightBuilder.sizeHint(fab.size)
87+
fab.foreach { case (k, (a, b)) =>
88+
leftBuilder += k -> a
89+
rightBuilder += k -> b
90+
}
91+
(leftBuilder.result(), rightBuilder.result())
92+
}
93+
8194
override def map2Eval[A, B, Z](
8295
fa: SortedMap[K, A],
8396
fb: Eval[SortedMap[K, B]]

core/src/main/scala/cats/instances/vector.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ trait VectorInstances extends cats.kernel.instances.VectorInstances {
218218

219219
override def algebra[A]: Monoid[Vector[A]] = kernel.instances.VectorMonoid[A]
220220

221+
override def unzip[A, B](fab: Vector[(A, B)]): (Vector[A], Vector[B]) =
222+
fab.unzip
223+
221224
def functor: Functor[Vector] = this
222225

223226
def align[A, B](fa: Vector[A], fb: Vector[B]): Vector[A Ior B] = {

core/src/main/scala/cats/package.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ package object cats {
109109
}
110110
override def distribute[F[_], A, B](fa: F[A])(f: A => B)(implicit F: Functor[F]): Id[F[B]] = F.map(fa)(f)
111111
override def map[A, B](fa: A)(f: A => B): B = f(fa)
112+
override def as[A, B](fa: A, b: B): B = b
113+
override def tupleLeft[A, B](fa: A, b: B): (B, A) = (b, fa)
114+
override def tupleRight[A, B](fa: A, b: B): (A, B) = (fa, b)
115+
override def fproduct[A, B](fa: A)(f: A => B): (A, B) = (fa, f(fa))
116+
override def fproductLeft[A, B](fa: A)(f: A => B): (B, A) = (f(fa), fa)
117+
override def unzip[A, B](fab: (A, B)): (A, B) = fab
112118
override def ap[A, B](ff: A => B)(fa: A): B = ff(fa)
113119
override def flatten[A](ffa: A): A = ffa
114120
override def map2[A, B, Z](fa: A, fb: B)(f: (A, B) => Z): Z = f(fa, fb)

0 commit comments

Comments
 (0)