Skip to content

Commit

Permalink
Merge branch 'master' into make-kernel-laws-consistent
Browse files Browse the repository at this point in the history
  • Loading branch information
Luka Jacobowitz committed Oct 4, 2017
2 parents c6ce594 + c131fe4 commit 8c60716
Show file tree
Hide file tree
Showing 44 changed files with 774 additions and 78 deletions.
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,22 @@ For more detail about Cats' motivations, go [here](http://typelevel.org/cats/mot

Cats is currently available for Scala 2.10, 2.11 and 2.12, and [Scala.js](http://www.scala-js.org/).

To get started with SBT, simply add the following to your `build.sbt`
file:

Cats relies on improved type inference via the fix for [SI-2112](https://issues.scala-lang.org/browse/SI-2712), which is not enabled by default. For **Scala 2.11.9 or later** you should add the following to your `build.sbt`:

```scala
scalacOptions += "-Ypartial-unification"

libraryDependencies += "org.typelevel" %% "cats-core" % "1.0.0-MF"
```

**Or**, if you need to support older versions of Scala you can use the [sbt-partial-unification](https://github.com/fiadliel/sbt-partial-unification#sbt-partial-unification) plugin which extends support back through **Scala 2.10.6 or later**, to add it, simply add this line to your `plugins.sbt`:

```scala
addSbtPlugin("org.lyranthe.sbt" % "partial-unification" % "1.1.0")
```

And then create the cats dependency, by adding the following to your `build.sbt`:

```scala
libraryDependencies += "org.typelevel" %% "cats-core" % "1.0.0-MF"
Expand All @@ -49,9 +63,6 @@ functionality, you can pick-and-choose from amongst these modules
* [`alleycats`](https://github.com/non/alleycats): cats instances and classes which are not lawful.
* [`mouse`](https://github.com/benhutchison/mouse): a small companion to cats that provides convenient syntax (aka extension methods)

#### Enhancing type inference

To use cats you'll need sometimes support for improved type inference. To enable it for any supported Scalac version, use this [sbt plugin](https://github.com/fiadliel/sbt-partial-unification#sbt-partial-unification).

Release notes for Cats are available in [CHANGES.md](https://github.com/typelevel/cats/blob/master/CHANGES.md).

Expand Down
118 changes: 117 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,123 @@ val binaryCompatibleVersion = "0.8.0"
val binaryCompatibleExceptions = {
import com.typesafe.tools.mima.core._
import com.typesafe.tools.mima.core.ProblemFilters._
Seq( //todo: remove these once we release 1.0.0-RC1
Seq( // todo: remove these once we release 1.0.0-RC1
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.QueueInstances.*"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.QueueInstances1.*"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.QueueInstances2.*"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.DurationInstances.*"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.MapInstances.catsKernelStdEqForMap"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.MapInstances.catsKernelStdMonoidForMap"),
exclude[ReversedMissingMethodProblem]("cats.kernel.instances.MapInstances.catsKernelStdHashForMap"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple12"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple7"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple4"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple13"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple11"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple1"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple7"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple16"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple22"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple1"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple14"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple4"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple20"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple19"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple10"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple17"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple18"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple3"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple9"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple6"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple3"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple12"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple22"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple6"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple19"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple10"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple9"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple21"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple15"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple13"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple16"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple20"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple14"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple5"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple2"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple8"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple17"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple5"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple15"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple21"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple11"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdPartialOrderForTuple2"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple8"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.TupleInstances.catsKernelStdEqForTuple18"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple9"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple16"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple22"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple3"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple6"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple21"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple18"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple12"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple15"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple8"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple2"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple5"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple20"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple14"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple17"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple4"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple11"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple7"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple1"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple10"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple19"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple13"),
exclude[ReversedMissingMethodProblem]("cats.kernel.instances.StreamInstances1.catsKernelStdHashForStream"),
exclude[ReversedMissingMethodProblem]("cats.kernel.instances.ListInstances1.catsKernelStdHashForList"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.SetInstances.catsKernelStdPartialOrderForSet"),
exclude[UpdateForwarderBodyProblem]("cats.kernel.instances.SetInstances.catsKernelStdSemilatticeForSet"),
exclude[ReversedMissingMethodProblem]("cats.kernel.instances.SetInstances.catsKernelStdHashForSet"),
exclude[ReversedMissingMethodProblem]("cats.kernel.instances.VectorInstances1.catsKernelStdHashForVector"),
exclude[DirectMissingMethodProblem]("cats.kernel.instances.BitSetInstances.catsKernelStdPartialOrderForBitSet"),
exclude[ReversedMissingMethodProblem]("cats.kernel.instances.BitSetInstances.cats$kernel$instances$BitSetInstances$_setter_$catsKernelStdOrderForBitSet_="),
exclude[ReversedMissingMethodProblem]("cats.kernel.instances.BitSetInstances.catsKernelStdOrderForBitSet"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple9"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple16"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple22"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple3"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple6"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple21"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple18"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple12"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple15"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple8"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple2"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple5"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple20"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple14"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple17"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple4"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple11"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple7"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple1"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple10"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple19"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.TupleInstances1.catsKernelStdHashForTuple13"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.EitherInstances1.catsStdEqForEither"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.EitherInstances.catsStdOrderForEither"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.EitherInstances.catsDataMonoidForEither"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.EitherInstances0.catsDataSemigroupForEither"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.EitherInstances0.catsStdHashForEither"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.EitherInstances0.catsStdPartialOrderForEither"),
exclude[ReversedMissingMethodProblem]("cats.kernel.instances.OptionInstances1.catsKernelStdHashForOption"),
exclude[ReversedMissingMethodProblem]("cats.kernel.instances.FunctionInstances0.catsKernelHashForFunction0"),
exclude[ReversedMissingMethodProblem]("cats.kernel.instances.EitherInstances0.catsStdHashForEither"),
exclude[DirectMissingMethodProblem]("cats.kernel.instances.all.package.catsKernelStdPartialOrderForBitSet"),
exclude[DirectMissingMethodProblem]("cats.kernel.instances.bitSet.package.catsKernelStdPartialOrderForBitSet"),
//todo: remove these once we release 1.0.0-RC1
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.QueueInstances.*"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.QueueInstances1.*"),
exclude[InheritedNewAbstractMethodProblem]("cats.kernel.instances.QueueInstances2.*"),
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/cats/instances/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ trait AllInstances
with EquivInstances
with FunctionInstances
with FutureInstances
with HashInstances
with ListInstances
with MapInstances
with MonoidInstances
Expand Down
16 changes: 16 additions & 0 deletions core/src/main/scala/cats/instances/hash.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cats
package instances


trait HashInstances {

implicit val catsContravariantForHash: Contravariant[Hash] =
new Contravariant[Hash] {
/**
* Derive a `Hash` for `B` given an `Hash[A]` and a function `B => A`.
*/
def contramap[A, B](ha: Hash[A])(f: B => A): Hash[B] = Hash.by(f)(ha)

}

}
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,15 @@ package object cats {
type Eq[A] = cats.kernel.Eq[A]
type PartialOrder[A] = cats.kernel.PartialOrder[A]
type Order[A] = cats.kernel.Order[A]
type Hash[A] = cats.kernel.Hash[A]
type Semigroup[A] = cats.kernel.Semigroup[A]
type Monoid[A] = cats.kernel.Monoid[A]
type Group[A] = cats.kernel.Group[A]

val Eq = cats.kernel.Eq
val PartialOrder = cats.kernel.PartialOrder
val Order = cats.kernel.Order
val Hash = cats.kernel.Hash
val Semigroup = cats.kernel.Semigroup
val Monoid = cats.kernel.Monoid
val Group = cats.kernel.Group
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/cats/syntax/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ trait AllSyntax
with FoldableSyntax
with FunctorSyntax
with GroupSyntax
with HashSyntax
with InvariantSyntax
with IorSyntax
with ListSyntax
Expand Down
18 changes: 18 additions & 0 deletions core/src/main/scala/cats/syntax/hash.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cats
package syntax

import cats.macros.Ops

trait HashSyntax {

implicit def catsSyntaxHash[A: Hash](a: A): HashOps[A] =
new HashOps[A](a)

}

final class HashOps[A: Hash](a: A) {
/**
* Gets the hash code of this object given an implicit `Hash` instance.
*/
def hash: Int = macro Ops.unop0[Int]
}
55 changes: 55 additions & 0 deletions kernel-laws/src/main/scala/cats/kernel/laws/HashLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package cats.kernel
package laws

import org.typelevel.discipline._
import org.scalacheck._
import org.scalacheck.Prop._

import scala.util.hashing._

object HashLaws {
def apply[A : Eq : Arbitrary]: HashLaws[A] =
new HashLaws[A] {
def Equ = implicitly[Eq[A]]
def Arb = implicitly[Arbitrary[A]]
}
}

/**
* @author Tongfei Chen
*/
trait HashLaws[A] extends Laws {

implicit def Equ: Eq[A]
implicit def Arb: Arbitrary[A]

def hash(implicit A: Hash[A]): HashProperties = new HashProperties(
name = "hash",
parent = None,
"compatibility-hash" -> forAll { (x: A, y: A) =>
!(A.eqv(x, y)) || (Hash.hash(x) == Hash.hash(y))
}
)

def sameAsUniversalHash(implicit A: Hash[A]): HashProperties = new HashProperties(
name = "sameAsUniversalHash",
parent = None,
"same-as-universal-hash" -> forAll { (x: A, y: A) =>
(A.hash(x) == x.hashCode) && (Hash.fromUniversalHashCode[A].hash(x) == x.hashCode()) &&
(A.eqv(x, y) == Hash.fromUniversalHashCode[A].eqv(x, y))
}
)

def sameAsScalaHashing(implicit catsHash: Hash[A], scalaHashing: Hashing[A]): HashProperties = new HashProperties(
name = "sameAsScalaHashing",
parent = None,
"same-as-scala-hashing" -> forAll { (x: A, y: A) =>
(catsHash.hash(x) == Hash.fromHashing(scalaHashing).hash(x)) &&
(catsHash.eqv(x, y) == Hash.fromHashing(scalaHashing).eqv(x, y))
}
)

class HashProperties(name: String, parent: Option[RuleSet], props: (String, Prop)*)
extends DefaultRuleSet(name, parent, props: _*)

}
Loading

0 comments on commit 8c60716

Please sign in to comment.