Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Followup to #751 (replaces #757) #843

Merged
merged 7 commits into from
Feb 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion core/src/main/scala/cats/Alternative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,21 @@ package cats

import simulacrum.typeclass

@typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F]
@typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] { self =>

/**
* Compose this `Alternative` instance with an [[Applicative]] instance.
*/
override def compose[G[_]](implicit GG: Applicative[G]): Alternative[λ[α => F[G[α]]]] =
new CompositeAlternative[F, G] {
implicit def F: Alternative[F] = self
implicit def G: Applicative[G] = GG
}
}

trait CompositeAlternative[F[_], G[_]]
extends Alternative[λ[α => F[G[α]]]] with CompositeApplicative[F, G] with CompositeMonoidK[F, G] {

implicit def F: Alternative[F]
implicit def G: Applicative[G]
}
16 changes: 16 additions & 0 deletions core/src/main/scala/cats/MonoidK.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ import simulacrum.typeclass
*/
def empty[A]: F[A]

/**
* Compose this MonoidK with an arbitrary type constructor
*/
override def composeK[G[_]]: MonoidK[λ[α => F[G[α]]]] =
new CompositeMonoidK[F, G] {
implicit def F: MonoidK[F] = self
}

/**
* Given a type A, create a concrete Monoid[F[A]].
*/
Expand All @@ -38,3 +46,11 @@ import simulacrum.typeclass
def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y)
}
}

trait CompositeMonoidK[F[_],G[_]]
extends MonoidK[λ[α => F[G[α]]]] with CompositeSemigroupK[F, G] {

implicit def F: MonoidK[F]

def empty[A]: F[G[A]] = F.empty
}
16 changes: 12 additions & 4 deletions core/src/main/scala/cats/SemigroupK.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ import simulacrum.{op, typeclass}
def combineK[A](x: F[A], y: F[A]): F[A]

/**
* Compose two SemigroupK intsances.
* Compose this SemigroupK with an arbitrary type constructor
*/
def compose[G[_]: SemigroupK]: SemigroupK[λ[α => F[G[α]]]] =
new SemigroupK[λ[α => F[G[α]]]] {
def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = self.combineK(x, y)
def composeK[G[_]]: SemigroupK[λ[α => F[G[α]]]] =
new CompositeSemigroupK[F, G] {
implicit def F: SemigroupK[F] = self
}

/**
Expand All @@ -44,3 +44,11 @@ import simulacrum.{op, typeclass}
def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y)
}
}

trait CompositeSemigroupK[F[_],G[_]]
extends SemigroupK[λ[α => F[G[α]]]] {

implicit def F: SemigroupK[F]

def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.combineK(x, y)
}
1 change: 1 addition & 0 deletions core/src/main/scala/cats/data/OneAnd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ trait OneAndLowPriority1 extends OneAndLowPriority0 {
def map[A, B](fa: OneAnd[F, A])(f: A => B): OneAnd[F, B] =
OneAnd(f(fa.head), F.map(fa.tail)(f))
}

}

trait OneAndLowPriority2 extends OneAndLowPriority1 {
Expand Down
32 changes: 20 additions & 12 deletions tests/src/test/scala/cats/tests/ComposeTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package cats
package tests

import cats.data.{ NonEmptyList, NonEmptyVector, OneAnd }
import cats.laws.discipline.{ ApplicativeTests, FoldableTests, CartesianTests, SemigroupKTests, arbitrary, eq }, arbitrary._, eq._
import cats.laws.discipline.{ AlternativeTests, ApplicativeTests, FoldableTests, CartesianTests, MonoidKTests, SemigroupKTests, arbitrary, eq }, arbitrary._, eq._
import org.scalacheck.Arbitrary

class ComposeTests extends CatsSuite {
Expand All @@ -12,6 +12,15 @@ class ComposeTests extends CatsSuite {
implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
PropertyCheckConfig(maxSize = 5, minSuccessful = 20)

{
// Alternative composition

implicit val alternativeListVector: Alternative[Lambda[A => List[Vector[A]]]] = Alternative[List] compose Alternative[Vector]
implicit val iso = CartesianTests.Isomorphisms.invariant[Lambda[A => List[Vector[A]]]]

checkAll("Alternative[Lambda[A => List[Vector[A]]]]", AlternativeTests[Lambda[A => List[Vector[A]]]].alternative[Int, Int, Int])
}

{
// Applicative composition

Expand All @@ -30,19 +39,18 @@ class ComposeTests extends CatsSuite {
}

{
// Reducible composition
// MonoidK composition

implicit val monoidKListVector: MonoidK[Lambda[A => List[Vector[A]]]] = MonoidK[List].composeK[Vector]

val nelReducible =
new NonEmptyReducible[NonEmptyList, List] {
def split[A](fa: NonEmptyList[A]): (A, List[A]) = (fa.head, fa.tail)
}
checkAll("MonoidK[Lambda[A => List[Vector[A]]]]", MonoidKTests[Lambda[A => List[Vector[A]]]].monoidK[Int])
}

val nevReducible =
new NonEmptyReducible[NonEmptyVector, Vector] {
def split[A](fa: NonEmptyVector[A]): (A, Vector[A]) = (fa.head, fa.tail)
}
{
// Reducible composition

implicit val reducibleListVector: Reducible[Lambda[A => NonEmptyList[NonEmptyVector[A]]]] = nelReducible compose nevReducible
implicit val reducibleListVector: Reducible[Lambda[A => NonEmptyList[NonEmptyVector[A]]]] =
Reducible[NonEmptyList] compose Reducible[NonEmptyVector]

// No Reducible-specific laws, so check the Foldable laws are satisfied
checkAll("Reducible[Lambda[A => List[Vector[A]]]]", FoldableTests[Lambda[A => NonEmptyList[NonEmptyVector[A]]]].foldable[Int, Int])
Expand All @@ -51,7 +59,7 @@ class ComposeTests extends CatsSuite {
{
// SemigroupK composition

implicit val semigroupKListVector: SemigroupK[Lambda[A => List[Vector[A]]]] = SemigroupK[List] compose SemigroupK[Vector]
implicit val semigroupKListVector: SemigroupK[Lambda[A => List[Vector[A]]]] = SemigroupK[List].composeK[Vector]

checkAll("SemigroupK[Lambda[A => List[Vector[A]]]]", SemigroupKTests[Lambda[A => List[Vector[A]]]].semigroupK[Int])
}
Expand Down