Skip to content

Commit 8549619

Browse files
committed
Override Foldable methods
- Override Foldable methods in a lot of instances (including NonEmptyReducible) - Override MonoidK algebra to get kernel Monoid instance - Add Reducible for Tuple2 I might have gone overboard with the "one element foldables" (Option, Either, ...).
1 parent 5a9717a commit 8549619

File tree

15 files changed

+307
-11
lines changed

15 files changed

+307
-11
lines changed

core/src/main/scala/cats/Foldable.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,6 @@ import simulacrum.typeclass
314314
def foldK[G[_], A](fga: F[G[A]])(implicit G: MonoidK[G]): G[A] =
315315
fold(fga)(G.algebra)
316316

317-
318317
/**
319318
* Find the first element matching the predicate, if one exists.
320319
*/

core/src/main/scala/cats/Reducible.scala

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ import simulacrum.typeclass
114114
* Traverse `F[A]` using `Apply[G]`.
115115
*
116116
* `A` values will be mapped into `G[B]` and combined using
117-
* `Applicative#map2`.
117+
* `Apply#map2`.
118118
*
119119
* This method is similar to [[Foldable.traverse_]]. There are two
120120
* main differences:
@@ -176,6 +176,16 @@ import simulacrum.typeclass
176176
case NonEmptyList(hd, tl) =>
177177
Reducible[NonEmptyList].reduce(NonEmptyList(hd, a :: intersperseList(tl, a)))
178178
}
179+
180+
override def isEmpty[A](fa: F[A]): Boolean = false
181+
182+
override def nonEmpty[A](fa: F[A]): Boolean = true
183+
184+
override def minimumOption[A](fa: F[A])(implicit A: Order[A]): Option[A] =
185+
Some(minimum(fa))
186+
187+
override def maximumOption[A](fa: F[A])(implicit A: Order[A]): Option[A] =
188+
Some(maximum(fa))
179189
}
180190

181191
/**
@@ -210,4 +220,55 @@ abstract class NonEmptyReducible[F[_], G[_]](implicit G: Foldable[G]) extends Re
210220
case None => Later(f(a))
211221
}
212222
}
223+
224+
override def size[A](fa: F[A]): Long = {
225+
val (_, tail) = split(fa)
226+
1 + G.size(tail)
227+
}
228+
229+
override def fold[A](fa: F[A])(implicit A: Monoid[A]): A = {
230+
val (a, ga) = split(fa)
231+
A.combine(a, G.fold(ga))
232+
}
233+
234+
override def find[A](fa: F[A])(f: A => Boolean): Option[A] = {
235+
val (a, ga) = split(fa)
236+
if (f(a)) Some(a) else G.find(ga)(f)
237+
}
238+
239+
override def exists[A](fa: F[A])(p: A => Boolean): Boolean = {
240+
val (a, ga) = split(fa)
241+
p(a) || G.exists(ga)(p)
242+
}
243+
244+
override def forall[A](fa: F[A])(p: A => Boolean): Boolean = {
245+
val (a, ga) = split(fa)
246+
p(a) && G.forall(ga)(p)
247+
}
248+
249+
override def toList[A](fa: F[A]): List[A] = {
250+
val (a, ga) = split(fa)
251+
a :: G.toList(ga)
252+
}
253+
254+
override def toNonEmptyList[A](fa: F[A]): NonEmptyList[A] = {
255+
val (a, ga) = split(fa)
256+
NonEmptyList(a, G.toList(ga))
257+
}
258+
259+
override def filter_[A](fa: F[A])(p: A => Boolean): List[A] = {
260+
val (a, ga) = split(fa)
261+
val filteredTail = G.filter_(ga)(p)
262+
if (p(a)) a :: filteredTail else filteredTail
263+
}
264+
265+
override def takeWhile_[A](fa: F[A])(p: A => Boolean): List[A] = {
266+
val (a, ga) = split(fa)
267+
if (p(a)) a :: G.takeWhile_(ga)(p) else Nil
268+
}
269+
270+
override def dropWhile_[A](fa: F[A])(p: A => Boolean): List[A] = {
271+
val (a, ga) = split(fa)
272+
if (p(a)) G.dropWhile_(ga)(p) else a :: G.toList(ga)
273+
}
213274
}

core/src/main/scala/cats/data/NonEmptyList.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,15 @@ private[data] sealed trait NonEmptyListInstances extends NonEmptyListInstances0
286286
NonEmptyList.fromListUnsafe(buf.result())
287287
}
288288

289+
override def fold[A](fa: NonEmptyList[A])(implicit A: Monoid[A]): A =
290+
fa.reduce
291+
292+
override def foldM[G[_], A, B](fa: NonEmptyList[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] =
293+
Foldable.iteratorFoldM(fa.toList.toIterator, z)(f)
294+
295+
override def find[A](fa: NonEmptyList[A])(f: A => Boolean): Option[A] =
296+
fa find f
297+
289298
override def forall[A](fa: NonEmptyList[A])(p: A => Boolean): Boolean =
290299
fa forall p
291300

core/src/main/scala/cats/data/NonEmptyVector.scala

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ private[data] sealed trait NonEmptyVectorInstances {
229229
def traverse[G[_], A, B](fa: NonEmptyVector[A])(f: (A) => G[B])(implicit G: Applicative[G]): G[NonEmptyVector[B]] =
230230
G.map2Eval(f(fa.head), Always(Traverse[Vector].traverse(fa.tail)(f)))(NonEmptyVector(_, _)).value
231231

232-
233232
override def foldLeft[A, B](fa: NonEmptyVector[A], b: B)(f: (B, A) => B): B =
234233
fa.foldLeft(b)(f)
235234

@@ -251,6 +250,21 @@ private[data] sealed trait NonEmptyVectorInstances {
251250
NonEmptyVector.fromVectorUnsafe(buf.result())
252251
}
253252

253+
override def fold[A](fa: NonEmptyVector[A])(implicit A: Monoid[A]): A =
254+
fa.reduce
255+
256+
override def foldM[G[_], A, B](fa: NonEmptyVector[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] =
257+
Foldable.iteratorFoldM(fa.toVector.toIterator, z)(f)
258+
259+
override def find[A](fa: NonEmptyVector[A])(f: A => Boolean): Option[A] =
260+
fa.find(f)
261+
262+
override def forall[A](fa: NonEmptyVector[A])(p: A => Boolean): Boolean =
263+
fa.forall(p)
264+
265+
override def exists[A](fa: NonEmptyVector[A])(p: A => Boolean): Boolean =
266+
fa.exists(p)
267+
254268
override def toList[A](fa: NonEmptyVector[A]): List[A] = fa.toVector.toList
255269

256270
override def toNonEmptyList[A](fa: NonEmptyVector[A]): NonEmptyList[A] =

core/src/main/scala/cats/data/Validated.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance
294294
fab.leftMap(f)
295295
}
296296

297+
// scalastyle:off method.length
297298
implicit def catsDataInstancesForValidated[E](implicit E: Semigroup[E]): Traverse[Validated[E, ?]] with ApplicativeError[Validated[E, ?], E] =
298299
new Traverse[Validated[E, ?]] with ApplicativeError[Validated[E, ?], E] {
299300
def traverse[F[_]: Applicative, A, B](fa: Validated[E, A])(f: A => F[B]): F[Validated[E, B]] =
@@ -323,7 +324,39 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance
323324
case v @ Validated.Valid(_) => v
324325
}
325326
def raiseError[A](e: E): Validated[E, A] = Validated.Invalid(e)
327+
328+
override def reduceLeftToOption[A, B](fa: Validated[E, A])(f: A => B)(g: (B, A) => B): Option[B] =
329+
fa.map(f).toOption
330+
331+
override def reduceRightToOption[A, B](fa: Validated[E, A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[Option[B]] =
332+
Now(fa.map(f).toOption)
333+
334+
override def reduceLeftOption[A](fa: Validated[E, A])(f: (A, A) => A): Option[A] =
335+
fa.toOption
336+
337+
override def reduceRightOption[A](fa: Validated[E, A])(f: (A, Eval[A]) => Eval[A]): Eval[Option[A]] =
338+
Now(fa.toOption)
339+
340+
override def size[A](fa: Validated[E, A]): Long = 1L
341+
342+
override def foldMap[A, B](fa: Validated[E, A])(f: A => B)(implicit B: Monoid[B]): B =
343+
fa.fold(_ => B.empty, f)
344+
345+
override def find[A](fa: Validated[E, A])(f: A => Boolean): Option[A] =
346+
fa.toOption.filter(f)
347+
348+
override def exists[A](fa: Validated[E, A])(p: A => Boolean): Boolean =
349+
fa.exists(p)
350+
351+
override def forall[A](fa: Validated[E, A])(p: A => Boolean): Boolean =
352+
fa.forall(p)
353+
354+
override def toList[A](fa: Validated[E, A]): List[A] =
355+
fa.fold(_ => Nil, _ :: Nil)
356+
357+
override def isEmpty[A](fa: Validated[E, A]): Boolean = fa.isInvalid
326358
}
359+
// scalastyle:on method.length
327360
}
328361

329362
private[data] sealed abstract class ValidatedInstances1 extends ValidatedInstances2 {

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,47 @@ trait EitherInstances extends cats.kernel.instances.EitherInstances {
8383

8484
override def attempt[B](fab: Either[A, B]): Either[A, Either[A, B]] =
8585
Right(fab)
86+
8687
override def recover[B](fab: Either[A, B])(pf: PartialFunction[A, B]): Either[A, B] =
8788
fab recover pf
89+
8890
override def recoverWith[B](fab: Either[A, B])(pf: PartialFunction[A, Either[A, B]]): Either[A, B] =
8991
fab recoverWith pf
92+
9093
override def ensure[B](fab: Either[A, B])(error: => A)(predicate: B => Boolean): Either[A, B] =
9194
fab.ensure(error)(predicate)
95+
96+
override def reduceLeftToOption[B, C](fab: Either[A, B])(f: B => C)(g: (C, B) => C): Option[C] =
97+
fab.right.map(f).toOption
98+
99+
override def reduceRightToOption[B, C](fab: Either[A, B])(f: B => C)(g: (B, Eval[C]) => Eval[C]): Eval[Option[C]] =
100+
Now(fab.right.map(f).toOption)
101+
102+
override def reduceLeftOption[B](fab: Either[A, B])(f: (B, B) => B): Option[B] =
103+
fab.right.toOption
104+
105+
override def reduceRightOption[B](fab: Either[A, B])(f: (B, Eval[B]) => Eval[B]): Eval[Option[B]] =
106+
Now(fab.right.toOption)
107+
108+
override def size[B](fab: Either[A, B]): Long = 1L
109+
110+
override def foldMap[B, C](fab: Either[A, B])(f: B => C)(implicit C: Monoid[C]): C =
111+
fab.fold(_ => C.empty, f)
112+
113+
override def find[B](fab: Either[A, B])(f: B => Boolean): Option[B] =
114+
fab.fold(_ => None, r => if (f(r)) Some(r) else None)
115+
116+
override def exists[B](fab: Either[A, B])(p: B => Boolean): Boolean =
117+
fab.right.exists(p)
118+
119+
override def forall[B](fab: Either[A, B])(p: B => Boolean): Boolean =
120+
fab.right.forall(p)
121+
122+
override def toList[B](fab: Either[A, B]): List[B] =
123+
fab.fold(_ => Nil, _ :: Nil)
124+
125+
override def isEmpty[B](fab: Either[A, B]): Boolean =
126+
fab.isLeft
92127
}
93128
// scalastyle:on method.length
94129

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ trait ListInstances extends cats.kernel.instances.ListInstances {
8686
override def fold[A](fa: List[A])(implicit A: Monoid[A]): A = A.combineAll(fa)
8787

8888
override def toList[A](fa: List[A]): List[A] = fa
89+
90+
override def reduceLeftOption[A](fa: List[A])(f: (A, A) => A): Option[A] =
91+
fa.reduceLeftOption(f)
92+
93+
override def find[A](fa: List[A])(f: A => Boolean): Option[A] = fa.find(f)
94+
95+
override def filter_[A](fa: List[A])(p: A => Boolean): List[A] = fa.filter(p)
96+
97+
override def takeWhile_[A](fa: List[A])(p: A => Boolean): List[A] = fa.takeWhile(p)
98+
99+
override def dropWhile_[A](fa: List[A])(p: A => Boolean): List[A] = fa.dropWhile(p)
100+
101+
override def algebra[A]: Monoid[List[A]] = new kernel.instances.ListMonoid[A]
89102
}
90103

91104
implicit def catsStdShowForList[A:Show]: Show[List[A]] =

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,46 @@ trait OptionInstances extends cats.kernel.instances.OptionInstances {
7171
override def filter[A](fa: Option[A])(p: A => Boolean): Option[A] =
7272
fa.filter(p)
7373

74+
override def reduceLeftToOption[A, B](fa: Option[A])(f: A => B)(g: (B, A) => B): Option[B] =
75+
fa.map(f)
76+
77+
override def reduceRightToOption[A, B](fa: Option[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[Option[B]] =
78+
Now(fa.map(f))
79+
80+
override def reduceLeftOption[A](fa: Option[A])(f: (A, A) => A): Option[A] = fa
81+
82+
override def reduceRightOption[A](fa: Option[A])(f: (A, Eval[A]) => Eval[A]): Eval[Option[A]] =
83+
Now(fa)
84+
85+
override def minimumOption[A](fa: Option[A])(implicit A: Order[A]): Option[A] = fa
86+
87+
override def maximumOption[A](fa: Option[A])(implicit A: Order[A]): Option[A] = fa
88+
89+
override def size[A](fa: Option[A]): Long = 1L
90+
91+
override def foldMap[A, B](fa: Option[A])(f: A => B)(implicit B: Monoid[B]): B =
92+
fa.fold(B.empty)(f)
93+
94+
override def find[A](fa: Option[A])(f: A => Boolean): Option[A] =
95+
fa.filter(f)
96+
7497
override def exists[A](fa: Option[A])(p: A => Boolean): Boolean =
7598
fa.exists(p)
7699

77100
override def forall[A](fa: Option[A])(p: A => Boolean): Boolean =
78101
fa.forall(p)
79102

103+
override def toList[A](fa: Option[A]): List[A] = fa.toList
104+
105+
override def filter_[A](fa: Option[A])(p: A => Boolean): List[A] =
106+
fa.filter(p).toList
107+
108+
override def takeWhile_[A](fa: Option[A])(p: A => Boolean): List[A] =
109+
fa.filter(p).toList
110+
111+
override def dropWhile_[A](fa: Option[A])(p: A => Boolean): List[A] =
112+
fa.filterNot(p).toList
113+
80114
override def isEmpty[A](fa: Option[A]): Boolean =
81115
fa.isEmpty
82116
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ trait SetInstances extends cats.kernel.instances.SetInstances {
3434
override def fold[A](fa: Set[A])(implicit A: Monoid[A]): A = A.combineAll(fa)
3535

3636
override def toList[A](fa: Set[A]): List[A] = fa.toList
37+
38+
override def reduceLeftOption[A](fa: Set[A])(f: (A, A) => A): Option[A] =
39+
fa.reduceLeftOption(f)
40+
41+
override def find[A](fa: Set[A])(f: A => Boolean): Option[A] = fa.find(f)
3742
}
3843

3944
implicit def catsStdShowForSet[A:Show]: Show[Set[A]] = new Show[Set[A]] {

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ trait StreamInstances extends cats.kernel.instances.StreamInstances {
113113
override def fold[A](fa: Stream[A])(implicit A: Monoid[A]): A = A.combineAll(fa)
114114

115115
override def toList[A](fa: Stream[A]): List[A] = fa.toList
116+
117+
override def reduceLeftOption[A](fa: Stream[A])(f: (A, A) => A): Option[A] =
118+
fa.reduceLeftOption(f)
119+
120+
override def find[A](fa: Stream[A])(f: A => Boolean): Option[A] = fa.find(f)
121+
122+
override def algebra[A]: Monoid[Stream[A]] = new kernel.instances.StreamMonoid[A]
116123
}
117124

118125
implicit def catsStdShowForStream[A: Show]: Show[Stream[A]] =

0 commit comments

Comments
 (0)