Skip to content

Commit

Permalink
NonEmptyList comonad is not commutative
Browse files Browse the repository at this point in the history
  • Loading branch information
kailuowang committed Jul 6, 2017
1 parent bcc38a5 commit 5cfef8c
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 13 deletions.
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/data/NonEmptyList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,8 @@ object NonEmptyList extends NonEmptyListInstances {
private[data] sealed trait NonEmptyListInstances extends NonEmptyListInstances0 {

implicit val catsDataInstancesForNonEmptyList: SemigroupK[NonEmptyList] with Reducible[NonEmptyList]
with CommutativeComonad[NonEmptyList] with NonEmptyTraverse[NonEmptyList] with Monad[NonEmptyList] =
new NonEmptyReducible[NonEmptyList, List] with SemigroupK[NonEmptyList] with CommutativeComonad[NonEmptyList]
with Comonad[NonEmptyList] with NonEmptyTraverse[NonEmptyList] with Monad[NonEmptyList] =
new NonEmptyReducible[NonEmptyList, List] with SemigroupK[NonEmptyList] with Comonad[NonEmptyList]
with Monad[NonEmptyList] with NonEmptyTraverse[NonEmptyList] {

def combineK[A](a: NonEmptyList[A], b: NonEmptyList[A]): NonEmptyList[A] =
Expand Down
3 changes: 3 additions & 0 deletions laws/src/main/scala/cats/laws/ArrowLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ trait ArrowLaws[F[_, _]] extends CategoryLaws[F] with StrongLaws[F] {
def arrowAssociation[A, B, C, D](f: F[A, B]): IsEq[F[((A, C), D), (B, (C, D))]] =
(f.first[C].first[D] andThen F.lift(assoc[B, C, D])) <-> (F.lift(assoc[A, C, D]) andThen f.first[(C, D)])

def splitConsistentWithAndThen[A, B, C, D](f: F[A, B], g: F[C, D]): IsEq[F[(A, C), (B, D)]] =
F.split(f, g) <-> (f.first andThen g.second)

private def fst[A, B](p: (A, B)): A = p._1

private def assoc[A, B, C](p: ((A, B), C)): (A, (B, C)) = (p._1._1, (p._1._2, p._2))
Expand Down
7 changes: 5 additions & 2 deletions laws/src/main/scala/cats/laws/discipline/Arbitrary.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ object arbitrary extends ArbitraryInstances0 {
B.perturb(seed, _),
(a, b) => A.perturb(B.perturb(seed, b), a)))

implicit def catsLawsArbitraryForCokleisli[F[_], A, B](implicit AFA: Arbitrary[F[A]], CFA: Cogen[F[A]], B: Arbitrary[B]): Arbitrary[Cokleisli[F, A, B]] =
Arbitrary(Arbitrary.arbitrary[F[A] => B].map(Cokleisli(_)))

implicit def catsLawsArbitraryForOptionT[F[_], A](implicit F: Arbitrary[F[Option[A]]]): Arbitrary[OptionT[F, A]] =
Arbitrary(F.arbitrary.map(OptionT.apply))
Expand Down Expand Up @@ -161,6 +159,9 @@ object arbitrary extends ArbitraryInstances0 {
implicit def catsLawArbitraryForReader[A: Arbitrary: Cogen, B: Arbitrary]: Arbitrary[Reader[A, B]] =
catsLawsArbitraryForKleisli[Id, A, B]

implicit def catsLawArbitraryForCokleisliId[A: Arbitrary: Cogen, B: Arbitrary]: Arbitrary[Cokleisli[Id, A, B]] =
catsLawsArbitraryForCokleisli[Id, A, B]

implicit def catsLawsAribtraryForReaderWriterStateT[F[_]: Applicative, E, S, L, A](implicit F: Arbitrary[(E, S) => F[(L, S, A)]]): Arbitrary[ReaderWriterStateT[F, E, S, L, A]] =
Arbitrary(F.arbitrary.map(ReaderWriterStateT(_)))
}
Expand All @@ -179,4 +180,6 @@ private[discipline] sealed trait ArbitraryInstances0 {
implicit def catsLawsArbitraryForKleisli[F[_], A, B](implicit AA: Arbitrary[A], CA: Cogen[A], F: Arbitrary[F[B]]): Arbitrary[Kleisli[F, A, B]] =
Arbitrary(Arbitrary.arbitrary[A => F[B]].map(Kleisli(_)))

implicit def catsLawsArbitraryForCokleisli[F[_], A, B](implicit AFA: Arbitrary[F[A]], CFA: Cogen[F[A]], B: Arbitrary[B]): Arbitrary[Cokleisli[F, A, B]] =
Arbitrary(Arbitrary.arbitrary[F[A] => B].map(Cokleisli(_)))
}
3 changes: 2 additions & 1 deletion laws/src/main/scala/cats/laws/discipline/ArrowTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ trait ArrowTests[F[_, _]] extends CategoryTests[F] with StrongTests[F] {
"arrow functor" -> forAll(laws.arrowFunctor[A, B, C, D] _),
"arrow exchange" -> forAll(laws.arrowExchange[A, B, C, D] _),
"arrow unit" -> forAll(laws.arrowUnit[A, B, C] _),
"arrow association" -> forAll(laws.arrowAssociation[A, B, C, D] _)
"arrow association" -> forAll(laws.arrowAssociation[A, B, C, D] _),
"split consistent with andThen" -> forAll(laws.splitConsistentWithAndThen[A, B, C, D] _)
)
}
}
Expand Down
10 changes: 5 additions & 5 deletions tests/src/test/scala/cats/tests/CokleisliTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ class CokleisliTests extends SlowCatsSuite {
checkAll("Contravariant[Cokleisli[Option, ?, Int]]", SerializableTests.serializable(Contravariant[Cokleisli[Option, ?, Int]]))

{
// Ceremony to help scalac to do the right thing, see also #267.
type CokleisliNEL[A, B] = Cokleisli[NonEmptyList, A, B]
implicit def cokleisliIdEq[A, B](implicit A: Arbitrary[A], FB: Eq[B]): Eq[Cokleisli[Id, A, B]] =
Eq.by[Cokleisli[Id, A, B], A => B](_.run)

checkAll("Cokleisli[NonEmptyList, Int, Int]", CommutativeArrowTests[CokleisliNEL].commutativeArrow[Int, Int, Int, Int, Int, Int])
checkAll("CommutativeArrow[Cokleisli[NonEmptyList, ?, ?]]", SerializableTests.serializable(CommutativeArrow[CokleisliNEL]))
checkAll("Cokleisli[Id, Int, Int]", CommutativeArrowTests[Cokleisli[Id, ?, ?]].commutativeArrow[Int, Int, Int, Int, Int, Int])
checkAll("CommutativeArrow[Cokleisli[Id, ?, ?]]", SerializableTests.serializable(CommutativeArrow[Cokleisli[Id, ?, ?]]))
}

{
// More ceremony, see above
// Ceremony to help scalac to do the right thing, see also #267.
type CokleisliNELE[A] = Cokleisli[NonEmptyList, A, A]

{
Expand Down
6 changes: 3 additions & 3 deletions tests/src/test/scala/cats/tests/NonEmptyListTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package tests
import cats.kernel.laws.{GroupLaws, OrderLaws}

import cats.data.NonEmptyList
import cats.laws.discipline.{CommutativeComonadTests, SemigroupKTests, MonadTests, SerializableTests, NonEmptyTraverseTests, ReducibleTests }
import cats.laws.discipline.{ComonadTests, SemigroupKTests, MonadTests, SerializableTests, NonEmptyTraverseTests, ReducibleTests }
import cats.laws.discipline.arbitrary._

class NonEmptyListTests extends CatsSuite {
Expand All @@ -29,8 +29,8 @@ class NonEmptyListTests extends CatsSuite {
checkAll("NonEmptyList[Int]", GroupLaws[NonEmptyList[Int]].semigroup)
checkAll("Semigroup[NonEmptyList[Int]]", SerializableTests.serializable(Semigroup[NonEmptyList[Int]]))

checkAll("NonEmptyList[Int]", CommutativeComonadTests[NonEmptyList].commutativeComonad[Int, Int, Int])
checkAll("CommutativeComonad[NonEmptyList]", SerializableTests.serializable(CommutativeComonad[NonEmptyList]))
checkAll("NonEmptyList[Int]", ComonadTests[NonEmptyList].comonad[Int, Int, Int])
checkAll("Comonad[NonEmptyList]", SerializableTests.serializable(Comonad[NonEmptyList]))

checkAll("NonEmptyList[ListWrapper[Int]]", OrderLaws[NonEmptyList[ListWrapper[Int]]].eqv)
checkAll("Eq[NonEmptyList[ListWrapper[Int]]]", SerializableTests.serializable(Eq[NonEmptyList[ListWrapper[Int]]]))
Expand Down

0 comments on commit 5cfef8c

Please sign in to comment.