-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Welcome, Alleycats #1984
Merged
Merged
Welcome, Alleycats #1984
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't actually know why this shouldn't be in cats-core. What is the problem exactly?
Foldable
is lawless to begin with.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK
Iterable
's only method isiterator
which isn't exactly referentially transparent, no?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But that is the only method you need to implement Foldable. And I don’t see why creating a new Iterator is not referentially transparent. It certainly is for all instances of Iterable is the standard library AFAIK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if all
Iterable
are actuallyFoldable
, what aboutStream
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn’t Stream have a Foldable instance in cats already? What prevents it from being Foldable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are right,
Stream
isFoldable
. Yeah, I don't see why we couldn't moveFoldable
ofIterable
into core.