Skip to content

Commit a38a588

Browse files
edmundnobleEdmund Noble
authored and
Edmund Noble
committed
Make NonEmptyList covariant
Also change nonemptyvector's variance
1 parent 468e753 commit a38a588

File tree

3 files changed

+37
-35
lines changed

3 files changed

+37
-35
lines changed

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

+15-14
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import scala.collection.mutable.ListBuffer
1212
* A data type which represents a non empty list of A, with
1313
* single element (head) and optional structure (tail).
1414
*/
15-
final case class NonEmptyList[A](head: A, tail: List[A]) {
15+
final case class NonEmptyList[+A](head: A, tail: List[A]) {
1616

1717
/**
1818
* Return the head and tail into a single list
@@ -25,13 +25,14 @@ final case class NonEmptyList[A](head: A, tail: List[A]) {
2525
def map[B](f: A => B): NonEmptyList[B] =
2626
NonEmptyList(f(head), tail.map(f))
2727

28-
def ++(l: List[A]): NonEmptyList[A] =
28+
def ++[AA >: A](l: List[AA]): NonEmptyList[AA] =
2929
NonEmptyList(head, tail ++ l)
3030

3131
def flatMap[B](f: A => NonEmptyList[B]): NonEmptyList[B] =
3232
f(head) ++ tail.flatMap(f andThen (_.toList))
3333

34-
def ::(a: A): NonEmptyList[A] = NonEmptyList(a, head :: tail)
34+
def ::[AA >: A](a: AA): NonEmptyList[AA] =
35+
NonEmptyList(a, head :: tail)
3536

3637
/**
3738
* Remove elements not matching the predicate
@@ -68,7 +69,7 @@ final case class NonEmptyList[A](head: A, tail: List[A]) {
6869
/**
6970
* Append another NonEmptyList
7071
*/
71-
def concat(other: NonEmptyList[A]): NonEmptyList[A] =
72+
def concat[AA >: A](other: NonEmptyList[AA]): NonEmptyList[AA] =
7273
NonEmptyList(head, tail ::: other.toList)
7374

7475
/**
@@ -105,8 +106,8 @@ final case class NonEmptyList[A](head: A, tail: List[A]) {
105106
/**
106107
* Left-associative reduce using f.
107108
*/
108-
def reduceLeft(f: (A, A) => A): A =
109-
tail.foldLeft(head)(f)
109+
def reduceLeft[AA >: A](f: (AA, AA) => AA): AA =
110+
tail.foldLeft[AA](head)(f)
110111

111112
def traverse[G[_], B](f: A => G[B])(implicit G: Applicative[G]): G[NonEmptyList[B]] =
112113
G.map2Eval(f(head), Always(Traverse[List].traverse(tail)(f)))(NonEmptyList(_, _)).value
@@ -123,23 +124,23 @@ final case class NonEmptyList[A](head: A, tail: List[A]) {
123124
NonEmptyList(f(this), consume(tail))
124125
}
125126

126-
def ===(o: NonEmptyList[A])(implicit A: Eq[A]): Boolean =
127-
(this.head === o.head) && this.tail === o.tail
127+
def ===[AA >: A](o: NonEmptyList[AA])(implicit AA: Eq[AA]): Boolean =
128+
((this.head: AA) === o.head) && (this.tail: List[AA]) === o.tail
128129

129-
def show(implicit A: Show[A]): String =
130-
toList.iterator.map(A.show).mkString("NonEmptyList(", ", ", ")")
130+
def show[AA >: A](implicit AA: Show[AA]): String =
131+
toList.iterator.map(AA.show).mkString("NonEmptyList(", ", ", ")")
131132

132133
override def toString: String = s"NonEmpty$toList"
133134

134135
/**
135136
* Remove duplicates. Duplicates are checked using `Order[_]` instance.
136137
*/
137-
def distinct(implicit O: Order[A]): NonEmptyList[A] = {
138+
def distinct[AA >: A](implicit O: Order[AA]): NonEmptyList[AA] = {
138139
implicit val ord = O.toOrdering
139140

140-
val buf = ListBuffer.empty[A]
141-
tail.foldLeft(TreeSet(head)) { (elementsSoFar, a) =>
142-
if (elementsSoFar(a)) elementsSoFar else { buf += a; elementsSoFar + a }
141+
val buf = ListBuffer.empty[AA]
142+
tail.foldLeft(TreeSet(head: AA)) { (elementsSoFar, b) =>
143+
if (elementsSoFar(b)) elementsSoFar else { buf += b; elementsSoFar + b }
143144
}
144145

145146
NonEmptyList(head, buf.toList)

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

+21-20
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import cats.instances.vector._
1212
* `NonEmptyVector`. However, due to https://issues.scala-lang.org/browse/SI-6601, on
1313
* Scala 2.10, this may be bypassed due to a compiler bug.
1414
*/
15-
final class NonEmptyVector[A] private (val toVector: Vector[A]) extends AnyVal {
15+
final class NonEmptyVector[+A] private (val toVector: Vector[A]) extends AnyVal {
1616

1717
/** Gets the element at the index, if it exists */
1818
def get(i: Int): Option[A] =
@@ -22,15 +22,15 @@ final class NonEmptyVector[A] private (val toVector: Vector[A]) extends AnyVal {
2222
def getUnsafe(i: Int): A = toVector(i)
2323

2424
/** Updates the element at the index, if it exists */
25-
def updated(i: Int, a: A): Option[NonEmptyVector[A]] =
25+
def updated[AA >: A](i: Int, a: AA): Option[NonEmptyVector[AA]] =
2626
if (toVector.isDefinedAt(i)) Some(new NonEmptyVector(toVector.updated(i, a))) else None
2727

2828
/**
2929
* Updates the element at the index, or throws an `IndexOutOfBoundsException`
3030
* if none exists (if `i` does not satisfy `0 <= i < length`).
3131
*/
32-
def updatedUnsafe(i: Int, a: A):
33-
NonEmptyVector[A] = new NonEmptyVector(toVector.updated(i, a))
32+
def updatedUnsafe[AA >: A](i: Int, a: AA):
33+
NonEmptyVector[AA] = new NonEmptyVector(toVector.updated(i, a))
3434

3535
def head: A = toVector.head
3636

@@ -63,37 +63,37 @@ final class NonEmptyVector[A] private (val toVector: Vector[A]) extends AnyVal {
6363
/**
6464
* Alias for [[concat]]
6565
*/
66-
def ++(other: Vector[A]): NonEmptyVector[A] = concat(other)
66+
def ++[AA >: A](other: Vector[AA]): NonEmptyVector[AA] = concat(other)
6767

6868
/**
6969
* Append another `Vector` to this, producing a new `NonEmptyVector`.
7070
*/
71-
def concat(other: Vector[A]): NonEmptyVector[A] = new NonEmptyVector(toVector ++ other)
71+
def concat[AA >: A](other: Vector[AA]): NonEmptyVector[AA] = new NonEmptyVector(toVector ++ other)
7272

7373
/**
7474
* Append another `NonEmptyVector` to this, producing a new `NonEmptyVector`.
7575
*/
76-
def concatNev(other: NonEmptyVector[A]): NonEmptyVector[A] = new NonEmptyVector(toVector ++ other.toVector)
76+
def concatNev[AA >: A](other: NonEmptyVector[AA]): NonEmptyVector[AA] = new NonEmptyVector(toVector ++ other.toVector)
7777

7878
/**
7979
* Append an item to this, producing a new `NonEmptyVector`.
8080
*/
81-
def append(a: A): NonEmptyVector[A] = new NonEmptyVector(toVector :+ a)
81+
def append[AA >: A](a: AA): NonEmptyVector[AA] = new NonEmptyVector(toVector :+ a)
8282

8383
/**
8484
* Alias for [[append]]
8585
*/
86-
def :+(a: A): NonEmptyVector[A] = append(a)
86+
def :+[AA >: A](a: AA): NonEmptyVector[AA] = append(a)
8787

8888
/**
8989
* Prepend an item to this, producing a new `NonEmptyVector`.
9090
*/
91-
def prepend(a: A): NonEmptyVector[A] = new NonEmptyVector(a +: toVector)
91+
def prepend[AA >: A](a: AA): NonEmptyVector[AA] = new NonEmptyVector(a +: toVector)
9292

9393
/**
9494
* Alias for [[prepend]]
9595
*/
96-
def +:(a: A): NonEmptyVector[A] = prepend(a)
96+
def +:[AA >: A](a: AA): NonEmptyVector[AA] = prepend(a)
9797

9898
/**
9999
* Find the first element matching the predicate, if one exists
@@ -137,13 +137,13 @@ final class NonEmptyVector[A] private (val toVector: Vector[A]) extends AnyVal {
137137
/**
138138
* Left-associative reduce using f.
139139
*/
140-
def reduceLeft(f: (A, A) => A): A =
141-
tail.foldLeft(head)(f)
140+
def reduceLeft[AA >: A](f: (AA, AA) => AA): AA =
141+
tail.foldLeft(head: AA)(f)
142142

143143
/**
144144
* Reduce using the Semigroup of A
145145
*/
146-
def reduce(implicit S: Semigroup[A]): A =
146+
def reduce[AA >: A](implicit S: Semigroup[AA]): AA =
147147
S.combineAllOption(toVector).get
148148

149149
/**
@@ -154,7 +154,8 @@ final class NonEmptyVector[A] private (val toVector: Vector[A]) extends AnyVal {
154154
* equality provided by Eq[_] instances, rather than using the
155155
* universal equality provided by .equals.
156156
*/
157-
def ===(that: NonEmptyVector[A])(implicit A: Eq[A]): Boolean = Eq[Vector[A]].eqv(toVector, that.toVector)
157+
def ===[AA >: A](that: NonEmptyVector[AA])(implicit A: Eq[AA]): Boolean =
158+
Eq[Vector[AA]].eqv(toVector, that.toVector)
158159

159160
/**
160161
* Typesafe stringification method.
@@ -163,8 +164,8 @@ final class NonEmptyVector[A] private (val toVector: Vector[A]) extends AnyVal {
163164
* values according to Show[_] instances, rather than using the
164165
* universal .toString method.
165166
*/
166-
def show(implicit A: Show[A]): String =
167-
s"NonEmpty${Show[Vector[A]].show(toVector)}"
167+
def show[AA >: A](implicit AA: Show[AA]): String =
168+
s"NonEmpty${Show[Vector[AA]].show(toVector)}"
168169

169170
def length: Int = toVector.length
170171

@@ -173,11 +174,11 @@ final class NonEmptyVector[A] private (val toVector: Vector[A]) extends AnyVal {
173174
/**
174175
* Remove duplicates. Duplicates are checked using `Order[_]` instance.
175176
*/
176-
def distinct(implicit O: Order[A]): NonEmptyVector[A] = {
177+
def distinct[AA >: A](implicit O: Order[AA]): NonEmptyVector[AA] = {
177178
implicit val ord = O.toOrdering
178179

179-
val buf = Vector.newBuilder[A]
180-
tail.foldLeft(TreeSet(head)) { (elementsSoFar, a) =>
180+
val buf = Vector.newBuilder[AA]
181+
tail.foldLeft(TreeSet(head: AA)) { (elementsSoFar, a) =>
181182
if (elementsSoFar(a)) elementsSoFar else { buf += a; elementsSoFar + a }
182183
}
183184

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package cats
22

33
package object data {
44
type NonEmptyStream[A] = OneAnd[Stream, A]
5-
type ValidatedNel[E, A] = Validated[NonEmptyList[E], A]
5+
type ValidatedNel[+E, +A] = Validated[NonEmptyList[E], A]
66

77
def NonEmptyStream[A](head: A, tail: Stream[A] = Stream.empty): NonEmptyStream[A] =
88
OneAnd(head, tail)

0 commit comments

Comments
 (0)