-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* moved alleycats in * address feedback / removed duplicated class
- Loading branch information
1 parent
9277979
commit ef76136
Showing
21 changed files
with
615 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package alleycats | ||
|
||
import cats.SemigroupK | ||
import export.imports | ||
import simulacrum.typeclass | ||
|
||
@typeclass trait ConsK[F[_]] { | ||
def cons[A](hd: A, tl: F[A]): F[A] | ||
} | ||
|
||
object ConsK extends ConsK0 { | ||
implicit def pureSemigroupKIsConsK[F[_]](implicit p: Pure[F], s: SemigroupK[F]): ConsK[F] = | ||
new ConsK[F] { | ||
def cons[A](hd: A, tl: F[A]): F[A] = s.combineK(p.pure(hd), tl) | ||
} | ||
} | ||
|
||
@imports[ConsK] | ||
trait ConsK0 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package alleycats | ||
|
||
import cats.{Eq, Monoid} | ||
import cats.syntax.eq._ | ||
import export.imports | ||
import simulacrum.typeclass | ||
import scala.collection.generic.CanBuildFrom | ||
|
||
@typeclass trait Empty[A] { | ||
def empty: A | ||
|
||
def isEmpty(a: A)(implicit ev: Eq[A]): Boolean = | ||
empty === a | ||
|
||
def nonEmpty(a: A)(implicit ev: Eq[A]): Boolean = | ||
empty =!= a | ||
} | ||
|
||
object Empty extends EmptyInstances0 { | ||
def apply[A](a: => A): Empty[A] = | ||
new Empty[A] { lazy val empty: A = a } | ||
} | ||
|
||
trait EmptyInstances0 extends EmptyInstances1 { | ||
implicit def iterableIsEmpty[CC[X] <: Iterable[X], A](implicit cbf: CanBuildFrom[CC[A], A, CC[A]]): Empty[CC[A]] = | ||
Empty(cbf().result) | ||
} | ||
|
||
trait EmptyInstances1 extends EmptyInstances2 { | ||
// If Monoid extended Empty then this could be an exported subclass instance provided by Monoid | ||
implicit def monoidIsEmpty[A: Monoid]: Empty[A] = | ||
Empty(Monoid[A].empty) | ||
} | ||
|
||
@imports[Empty] | ||
trait EmptyInstances2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package alleycats | ||
|
||
import export._ | ||
import simulacrum.typeclass | ||
|
||
@typeclass trait EmptyK[F[_]] { self => | ||
def empty[A]: F[A] | ||
|
||
def synthesize[A]: Empty[F[A]] = | ||
new Empty[F[A]] { | ||
def empty: F[A] = self.empty[A] | ||
} | ||
} | ||
|
||
@imports[EmptyK] | ||
object EmptyK | ||
|
||
@exports | ||
object EmptyKInstances { | ||
@export(Instantiated) | ||
implicit def instantiate[F[_], T](implicit ekf: EmptyK[F]): Empty[F[T]] = ekf.synthesize[T] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package alleycats | ||
|
||
import cats.{CoflatMap, Comonad} | ||
import export.imports | ||
import simulacrum.typeclass | ||
|
||
@typeclass trait Extract[F[_]] { | ||
def extract[A](fa: F[A]): A | ||
} | ||
|
||
object Extract extends Extract0 { | ||
// Ideally this would be an exported subclass instance provided by Comonad | ||
implicit def comonadIsExtract[F[_]](implicit ev: Comonad[F]): Extract[F] = | ||
new Extract[F] { | ||
def extract[A](fa: F[A]): A = ev.extract(fa) | ||
} | ||
|
||
// Ideally this would be an instance exported to Comonad | ||
implicit def extractCoflatMapIsComonad[F[_]](implicit e: Extract[F], cf: CoflatMap[F]): Comonad[F] = | ||
new Comonad[F] { | ||
def extract[A](fa: F[A]): A = e.extract(fa) | ||
override def map[A, B](fa: F[A])(f: A => B): F[B] = cf.map(fa)(f) | ||
def coflatMap[A, B](fa: F[A])(f: F[A] => B): F[B] = cf.coflatMap(fa)(f) | ||
} | ||
} | ||
|
||
@imports[Extract] | ||
trait Extract0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package alleycats | ||
|
||
import cats.{Eq, Monoid} | ||
import cats.syntax.eq._ | ||
import export.imports | ||
import simulacrum.typeclass | ||
|
||
@typeclass trait One[A] { | ||
def one: A | ||
|
||
def isOne(a: A)(implicit ev: Eq[A]): Boolean = | ||
one === a | ||
|
||
def nonOne(a: A)(implicit ev: Eq[A]): Boolean = | ||
one =!= a | ||
} | ||
|
||
object One extends One0 { | ||
def apply[A](a: => A): One[A] = | ||
new One[A] { lazy val one: A = a } | ||
} | ||
|
||
@imports[One] | ||
trait One0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package alleycats | ||
|
||
import cats.{Applicative, FlatMap, Monad} | ||
import export.imports | ||
import simulacrum.typeclass | ||
|
||
@typeclass trait Pure[F[_]] { | ||
def pure[A](a: A): F[A] | ||
} | ||
|
||
object Pure extends Pure0 { | ||
// Ideally this would be an exported subclass instance provided by Applicative | ||
implicit def applicativeIsPure[F[_]](implicit ev: Applicative[F]): Pure[F] = | ||
new Pure[F] { | ||
def pure[A](a: A): F[A] = ev.pure(a) | ||
} | ||
|
||
// Ideally this would be an instance exported to Monad | ||
implicit def pureFlatMapIsMonad[F[_]](implicit p: Pure[F], fm: FlatMap[F]): Monad[F] = | ||
new Monad[F] { | ||
def pure[A](a: A): F[A] = p.pure(a) | ||
override def map[A, B](fa: F[A])(f: A => B): F[B] = fm.map(fa)(f) | ||
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] = fm.flatMap(fa)(f) | ||
def tailRecM[A, B](a: A)(f: (A) => F[Either[A, B]]): F[B] = fm.tailRecM(a)(f) | ||
} | ||
} | ||
|
||
@imports[Pure] | ||
trait Pure0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package alleycats | ||
|
||
import cats.Eq | ||
import cats.syntax.eq._ | ||
import export.imports | ||
import simulacrum.typeclass | ||
|
||
@typeclass trait Zero[A] { | ||
def zero: A | ||
|
||
def isZero(a: A)(implicit ev: Eq[A]): Boolean = | ||
zero === a | ||
|
||
def nonZero(a: A)(implicit ev: Eq[A]): Boolean = | ||
zero =!= a | ||
} | ||
|
||
object Zero extends Zero0 { | ||
def apply[A](a: => A): Zero[A] = | ||
new Zero[A] { lazy val zero: A = a } | ||
} | ||
|
||
@imports[Zero] | ||
trait Zero0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package alleycats | ||
package std | ||
|
||
import export._ | ||
|
||
@reexports( | ||
EmptyKInstances, | ||
ListInstances, | ||
OptionInstances, | ||
SetInstances, | ||
TryInstances, | ||
IterableInstances | ||
) object all extends LegacySetInstances with LegacyTryInstances with LegacyIterableInstances |
27 changes: 27 additions & 0 deletions
27
alleycats-core/src/main/scala/alleycats/std/iterable.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package alleycats | ||
package std | ||
|
||
import cats.{Eval, Foldable} | ||
import export._ | ||
|
||
@reexports(IterableInstances) | ||
object iterable extends LegacyIterableInstances | ||
|
||
@exports | ||
object IterableInstances { | ||
@export(Orphan) | ||
implicit val exportIterableFoldable: Foldable[Iterable] = | ||
new Foldable[Iterable] { | ||
override def foldLeft[A, B](fa: Iterable[A], b: B)(f: (B, A) => B): B = fa.foldLeft(b)(f) | ||
|
||
override def foldRight[A, B](fa: Iterable[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = | ||
Foldable.iterateRight(fa, lb)(f) | ||
} | ||
|
||
} | ||
|
||
// TODO: remove when cats.Foldable support export-hook | ||
trait LegacyIterableInstances { | ||
implicit def legacyIterableFoldable(implicit e: ExportOrphan[Foldable[Iterable]]): Foldable[Iterable] = e.instance | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package alleycats | ||
package std | ||
|
||
import export._ | ||
|
||
@reexports(ListInstances) | ||
object list | ||
|
||
@exports | ||
object ListInstances { | ||
@export(Orphan) | ||
implicit val exportListEmptyK: EmptyK[List] = | ||
new EmptyK[List] { | ||
def empty[A]: List[A] = Nil | ||
} | ||
|
||
@export(Orphan) | ||
implicit val exportListConsK: ConsK[List] = | ||
new ConsK[List] { | ||
def cons[A](hd: A, tl: List[A]): List[A] = hd :: tl | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package alleycats | ||
package std | ||
|
||
import export._ | ||
|
||
@reexports(OptionInstances) | ||
object option | ||
|
||
@exports | ||
object OptionInstances { | ||
@export(Orphan) | ||
implicit val exportOptionEmptyK: EmptyK[Option] = | ||
new EmptyK[Option] { | ||
def empty[A]: Option[A] = None | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package alleycats.std | ||
|
||
import cats.{Applicative, Eval, Foldable, Monad, Traverse} | ||
import export._ | ||
|
||
import scala.annotation.tailrec | ||
|
||
@exports | ||
object SetInstances { | ||
// This method advertises parametricity, but relies on using | ||
// universal hash codes and equality, which hurts our ability to | ||
// rely on free theorems. | ||
// | ||
// Another problem some people have pointed out is the | ||
// non-associativity of map when using impure functions. For | ||
// example, consider the following expressions: | ||
// | ||
// import scala.util.Random | ||
// | ||
// val f = (_: Int) => 1 | ||
// val g = (_: Int) => Random.nextInt | ||
// | ||
// Set(1, 2, 3).map(f).map(g) | ||
// Set(1, 2, 3).map(f andThen g) | ||
// | ||
// The first Set will contain one random number, and the second will | ||
// contain three. Since `g` is not a function (speaking strictly) | ||
// this would not be considered a law violation, but it still makes | ||
// people uncomfortable. | ||
@export(Orphan) | ||
implicit val setMonad: Monad[Set] = | ||
new Monad[Set] { | ||
def pure[A](a: A): Set[A] = Set(a) | ||
override def map[A, B](fa: Set[A])(f: A => B): Set[B] = fa.map(f) | ||
def flatMap[A, B](fa: Set[A])(f: A => Set[B]): Set[B] = fa.flatMap(f) | ||
|
||
def tailRecM[A, B](a: A)(f: (A) => Set[Either[A, B]]): Set[B] = { | ||
val bldr = Set.newBuilder[B] | ||
|
||
@tailrec def go(set: Set[Either[A, B]]): Unit = { | ||
val lefts = set.foldLeft(Set[A]()) { (memo, either) => | ||
either.fold( | ||
memo + _, | ||
b => { | ||
bldr += b | ||
memo | ||
} | ||
) | ||
} | ||
if (lefts.isEmpty) | ||
() | ||
else | ||
go(lefts.flatMap(f)) | ||
} | ||
go(f(a)) | ||
bldr.result() | ||
} | ||
} | ||
|
||
// Since iteration order is not guaranteed for sets, folds and other | ||
// traversals may produce different results for input sets which | ||
// appear to be the same. | ||
@export(Orphan) | ||
implicit val setTraverse: Traverse[Set] = | ||
new Traverse[Set] { | ||
def foldLeft[A, B](fa: Set[A], b: B)(f: (B, A) => B): B = | ||
fa.foldLeft(b)(f) | ||
def foldRight[A, B](fa: Set[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = | ||
Foldable.iterateRight(fa, lb)(f) | ||
def traverse[G[_]: Applicative, A, B](sa: Set[A])(f: A => G[B]): G[Set[B]] = { | ||
val G = Applicative[G] | ||
sa.foldLeft(G.pure(Set.empty[B])) { (buf, a) => | ||
G.map2(buf, f(a))(_ + _) | ||
} | ||
} | ||
} | ||
} | ||
|
||
@reexports(SetInstances) | ||
object set extends LegacySetInstances | ||
|
||
// TODO: remove when cats.{ Set, Traverse } support export-hook | ||
trait LegacySetInstances { | ||
implicit def legacySetMonad(implicit e: ExportOrphan[Monad[Set]]): Monad[Set] = e.instance | ||
|
||
implicit def legacySetTraverse(implicit e: ExportOrphan[Traverse[Set]]): Traverse[Set] = e.instance | ||
} |
Oops, something went wrong.