From 3e41fc595ae8db46a73aade1e45a15f24ef0765c Mon Sep 17 00:00:00 2001 From: Edmund Noble Date: Tue, 25 Oct 2016 00:51:58 -0400 Subject: [PATCH] Make NonEmptyList covariant --- .../main/scala/cats/data/NonEmptyList.scala | 27 ++++++++++--------- core/src/main/scala/cats/data/package.scala | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/core/src/main/scala/cats/data/NonEmptyList.scala b/core/src/main/scala/cats/data/NonEmptyList.scala index 6dc3b7ca612..13f3b732f31 100644 --- a/core/src/main/scala/cats/data/NonEmptyList.scala +++ b/core/src/main/scala/cats/data/NonEmptyList.scala @@ -12,7 +12,7 @@ import scala.collection.mutable.ListBuffer * A data type which represents a non empty list of A, with * single element (head) and optional structure (tail). */ -final case class NonEmptyList[A](head: A, tail: List[A]) { +final case class NonEmptyList[+A](head: A, tail: List[A]) { /** * Return the head and tail into a single list @@ -25,13 +25,14 @@ final case class NonEmptyList[A](head: A, tail: List[A]) { def map[B](f: A => B): NonEmptyList[B] = NonEmptyList(f(head), tail.map(f)) - def ++(l: List[A]): NonEmptyList[A] = + def ++[AA >: A](l: List[AA]): NonEmptyList[AA] = NonEmptyList(head, tail ++ l) def flatMap[B](f: A => NonEmptyList[B]): NonEmptyList[B] = f(head) ++ tail.flatMap(f andThen (_.toList)) - def ::(a: A): NonEmptyList[A] = NonEmptyList(a, head :: tail) + def ::[AA >: A](a: AA): NonEmptyList[AA] = + NonEmptyList(a, head :: tail) /** * remove elements not matching the predicate @@ -45,7 +46,7 @@ final case class NonEmptyList[A](head: A, tail: List[A]) { /** * Append another NonEmptyList */ - def concat(other: NonEmptyList[A]): NonEmptyList[A] = + def concat[AA >: A](other: NonEmptyList[AA]): NonEmptyList[AA] = NonEmptyList(head, tail ::: other.toList) /** @@ -82,8 +83,8 @@ final case class NonEmptyList[A](head: A, tail: List[A]) { /** * Left-associative reduce using f. */ - def reduceLeft(f: (A, A) => A): A = - tail.foldLeft(head)(f) + def reduceLeft[AA >: A](f: (AA, AA) => AA): AA = + tail.foldLeft[AA](head)(f) def traverse[G[_], B](f: A => G[B])(implicit G: Applicative[G]): G[NonEmptyList[B]] = G.map2Eval(f(head), Always(Traverse[List].traverse(tail)(f)))(NonEmptyList(_, _)).value @@ -100,23 +101,23 @@ final case class NonEmptyList[A](head: A, tail: List[A]) { NonEmptyList(f(this), consume(tail)) } - def ===(o: NonEmptyList[A])(implicit A: Eq[A]): Boolean = - (this.head === o.head) && this.tail === o.tail + def ===[AA >: A](o: NonEmptyList[AA])(implicit AA: Eq[AA]): Boolean = + ((this.head: AA) === o.head) && (this.tail: List[AA]) === o.tail - def show(implicit A: Show[A]): String = - toList.iterator.map(A.show).mkString("NonEmptyList(", ", ", ")") + def show[AA >: A](implicit AA: Show[AA]): String = + toList.iterator.map(AA.show).mkString("NonEmptyList(", ", ", ")") override def toString: String = s"NonEmpty$toList" /** * Remove duplicates. Duplicates are checked using `Order[_]` instance. */ - def distinct(implicit O: Order[A]): NonEmptyList[A] = { + def distinct[AA >: A](implicit O: Order[AA]): NonEmptyList[A] = { implicit val ord = O.toOrdering val buf = ListBuffer.empty[A] - tail.foldLeft(TreeSet(head)) { (elementsSoFar, a) => - if (elementsSoFar(a)) elementsSoFar else { buf += a; elementsSoFar + a } + tail.foldLeft(TreeSet[AA](head)) { (elementsSoFar, b) => + if (elementsSoFar(b)) elementsSoFar else { buf += b; elementsSoFar + b } } NonEmptyList(head, buf.toList) diff --git a/core/src/main/scala/cats/data/package.scala b/core/src/main/scala/cats/data/package.scala index e66bf5d6c9b..396f22908d5 100644 --- a/core/src/main/scala/cats/data/package.scala +++ b/core/src/main/scala/cats/data/package.scala @@ -2,7 +2,7 @@ package cats package object data { type NonEmptyStream[A] = OneAnd[Stream, A] - type ValidatedNel[E, A] = Validated[NonEmptyList[E], A] + type ValidatedNel[+E, +A] = Validated[NonEmptyList[E], A] def NonEmptyStream[A](head: A, tail: Stream[A] = Stream.empty): NonEmptyStream[A] = OneAnd(head, tail)