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

Added merge (product) to Arrow for arrows composition #2063

Merged
merged 19 commits into from
Dec 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
28fe55a
methods merge and -< work fine, but test no!
marcobattaglia Dec 5, 2017
c2e451f
fix tests
kailuowang Dec 5, 2017
29c878c
ArrowLaws without parens around A in IsEq[F[A, (B, C)]]
Dec 5, 2017
4d88b6c
Merge pull request #1 from kailuowang/marco
marcobattaglia Dec 5, 2017
fa6aa46
added law and test for Arrow.combineAndByPass
Dec 5, 2017
4f1c522
Added two method to compose Arrows 'merge' and '-<'. See comment in …
Dec 5, 2017
d7d0d47
Merge branch 'master' of https://github.com/marcobattaglia/cats
Dec 5, 2017
5f1e1d6
Merge branch 'master' of https://github.com/marcobattaglia/cats
Dec 5, 2017
f80bcb5
Merge branch 'master' of https://github.com/marcobattaglia/cats
Dec 5, 2017
87ff6a6
added exclude [ReverseMissingMethodProblem]s for Arrow.merge, Arrow.c…
Dec 5, 2017
db2d224
solved doctest errors
marcobattaglia Dec 5, 2017
2c0bc19
Better format in scala doc html presentation. Schema of merge functio…
Dec 6, 2017
817831a
combineAndByPass has been renamed to combineAndBypass
Dec 6, 2017
91dfe26
Arrow.combineAndBypass now calculates f only one time instead twice
marcobattaglia Dec 7, 2017
17c6a9e
Arrow.combineAndBypass now calculates f only one time instead twice
marcobattaglia Dec 7, 2017
c53e368
Merge branch 'master' of https://github.com/marcobattaglia/cats
marcobattaglia Dec 7, 2017
ef5996f
deleted one line of comment
marcobattaglia Dec 7, 2017
5bd2889
the combineAndBypass '-<' function has been deleted. the merge functi…
marcobattaglia Dec 7, 2017
4caa33e
space margin of comment reformatted in Arrow as standard
marcobattaglia Dec 8, 2017
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
3 changes: 3 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ def mimaSettings(moduleName: String) = Seq(
import com.typesafe.tools.mima.core.ProblemFilters._
Seq(
exclude[ReversedMissingMethodProblem]("cats.syntax.FoldableSyntax.catsSyntaxFoldOps"),
exclude[ReversedMissingMethodProblem]("cats.arrow.Arrow.merge"),
exclude[ReversedMissingMethodProblem]("cats.arrow.Arrow#Ops.merge"),
exclude[ReversedMissingMethodProblem]("cats.arrow.Arrow#Ops.&&&"),
exclude[ReversedMissingMethodProblem]("cats.Traverse.unorderedTraverse"),
exclude[ReversedMissingMethodProblem]("cats.Traverse.unorderedSequence"),
exclude[InheritedNewAbstractMethodProblem]("cats.UnorderedTraverse.unorderedTraverse"),
Expand Down
26 changes: 24 additions & 2 deletions core/src/main/scala/cats/arrow/Arrow.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import simulacrum.typeclass
@typeclass trait Arrow[F[_, _]] extends Category[F] with Strong[F] { self =>

/**
* Lift a function into the context of an Arrow.
* Lift a function into the context of an Arrow.
*
* In the reference articles "Arrows are Promiscuous...", and in the corresponding Haskell
* library `Control.Arrow`, this function is called `arr`.
Expand All @@ -21,6 +21,7 @@ import simulacrum.typeclass

override def second[A, B, C](fa: F[A, B]): F[(C, A), (C, B)] = {
def swap[X, Y]: F[(X, Y), (Y, X)] = lift[(X, Y), (Y, X)] { case (x, y) => (y, x) }

compose(swap, compose(first[A, B, C](fa), swap))
}

Expand All @@ -40,9 +41,30 @@ import simulacrum.typeclass
* }}}
*
* Note that the arrow laws do not guarantee the non-interference between the _effects_ of
* `f` and `g` in the context of F. This means that `f *** g` may not be equivalent to `g *** f`.
* `f` and `g` in the context of F. This means that `f *** g` may not be equivalent to `g *** f`.
*/
@simulacrum.op("***", alias = true)
def split[A, B, C, D](f: F[A, B], g: F[C, D]): F[(A, C), (B, D)] =
andThen(first(f), second(g))

/**
* Create a new computation `F` that merge outputs of `f` and `g` both having the same input
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> val addEmpty: Int => Int = _ + 0
* scala> val multiplyEmpty: Int => Double= _ * 1d
* scala> val f: Int => (Int, Double) = addEmpty &&& multiplyEmpty
* scala> f(1)
* res0: (Int, Double) = (1,1.0)
* }}}
*
* Note that the arrow laws do not guarantee the non-interference between the _effects_ of
* `f` and `g` in the context of F. This means that `f &&& g` may not be equivalent to `g &&& f`.
*/
@simulacrum.op("&&&", alias = true)
def merge[A, B, C](f: F[A, B], g: F[A, C]): F[A, (B, C)] = {
andThen(lift((x: A) => (x, x)), split(f, g))
}
}
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 @@ -37,6 +37,9 @@ trait ArrowLaws[F[_, _]] extends CategoryLaws[F] with StrongLaws[F] {
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)

def mergeConsistentWithAndThen[A, B, C](f: F[A, B], g: F[A, C]): IsEq[F[A, (B, C)]] =
F.merge(f, g) <-> ((F.lift((x: A) => (x, x))) andThen F.split(f, g))

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
5 changes: 4 additions & 1 deletion laws/src/main/scala/cats/laws/discipline/ArrowTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ trait ArrowTests[F[_, _]] extends CategoryTests[F] with StrongTests[F] {
def arrow[A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, G: Arbitrary](implicit
ArbFAB: Arbitrary[F[A, B]],
ArbFBC: Arbitrary[F[B, C]],
ArbFAC: Arbitrary[F[A, C]],
ArbFCD: Arbitrary[F[C, D]],
ArbFDE: Arbitrary[F[D, E]],
ArbFEG: Arbitrary[F[E, G]],
Expand All @@ -31,6 +32,7 @@ trait ArrowTests[F[_, _]] extends CategoryTests[F] with StrongTests[F] {
EqFADCD: Eq[F[(A, D), (C, D)]],
EqFADCG: Eq[F[(A, D), (C, G)]],
EqFAEDE: Eq[F[(A, E), (D, E)]],
EqFABC: Eq[F[A, (B, C)]],
EqFEAED: Eq[F[(E, A), (E, D)]],
EqFACDBCD: Eq[F[((A, C), D), (B, (C, D))]]
): RuleSet =
Expand All @@ -49,7 +51,8 @@ trait ArrowTests[F[_, _]] extends CategoryTests[F] with StrongTests[F] {
"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] _),
"split consistent with andThen" -> forAll(laws.splitConsistentWithAndThen[A, B, C, D] _)
"split consistent with andThen" -> forAll(laws.splitConsistentWithAndThen[A, B, C, D] _),
"merge consistent with andThen" -> forAll(laws.mergeConsistentWithAndThen[A, B, C] _)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ trait CommutativeArrowTests[F[_, _]] extends ArrowTests[F] {

def commutativeArrow[A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, G: Arbitrary](implicit
ArbFAB: Arbitrary[F[A, B]],
ArbFAC: Arbitrary[F[A, C]],
ArbFBC: Arbitrary[F[B, C]],
ArbFCD: Arbitrary[F[C, D]],
ArbFDE: Arbitrary[F[D, E]],
Expand All @@ -26,6 +27,7 @@ trait CommutativeArrowTests[F[_, _]] extends ArrowTests[F] {
EqFAD: Eq[F[A, D]],
EqFAG: Eq[F[A, G]],
EqFACB: Eq[F[(A, C), B]],
EqFABC: Eq[F[A, (B, C)]],
EqFACBC: Eq[F[(A, C), (B, C)]],
EqFACBD: Eq[F[(A, C), (B, D)]],
EqFADCD: Eq[F[(A, D), (C, D)]],
Expand Down