@@ -4,23 +4,61 @@ package laws
44import cats .arrow .Strong
55import cats .syntax .profunctor ._
66import cats .syntax .strong ._
7- import cats .instances .function ._
87
98/**
109 * Laws that must be obeyed by any `cats.functor.Strong`.
10+ *
11+ * See: [[https://arxiv.org/abs/1406.4823 E. Rivas, M. Jaskelioff Notions of Computation as Monoids, Chapter 7 ]]
12+ * See: [[http://hackage.haskell.org/package/profunctors/docs/Data-Profunctor-Strong.html Haskell Data.Profunctor.Strong ]]
1113 */
1214trait StrongLaws [F [_, _]] extends ProfunctorLaws [F ] {
1315 implicit override def F : Strong [F ]
1416
15- def strongFirstDistributivity [A0 , A1 , B1 , B2 , C ](fab : F [A1 , B1 ],
16- f : A0 => A1 ,
17- g : B1 => B2 ): IsEq [F [(A0 , C ), (B2 , C )]] =
18- fab.dimap(f)(g).first[C ] <-> fab.first[C ].dimap(f.first[C ])(g.first[C ])
17+ private def swapTuple [X , Y ]: Tuple2 [X , Y ] => Tuple2 [Y , X ] = _.swap
1918
20- def strongSecondDistributivity [A0 , A1 , B1 , B2 , C ](fab : F [A1 , B1 ],
21- f : A0 => A1 ,
22- g : B1 => B2 ): IsEq [F [(C , A0 ), (C , B2 )]] =
23- fab.dimap(f)(g).second[C ] <-> fab.second[C ].dimap(f.second[C ])(g.second[C ])
19+ /** first' == dimap swap swap . second' */
20+ def firstIsSwappedSecond [A , B , C ](fab : F [A , B ]): IsEq [F [(A , C ), (B , C )]] =
21+ fab.first[C ] <-> fab.second[C ].dimap(swapTuple[A , C ])(swapTuple[C , B ])
22+
23+ /** second' == dimap swap swap . first' */
24+ def secondIsSwappedFirst [A , B , C ](fab : F [A , B ]): IsEq [F [(C , A ), (C , B )]] =
25+ fab.second[C ] <-> fab.first[C ].dimap(swapTuple[C , A ])(swapTuple[B , C ])
26+
27+ /** lmap fst == rmap fst . first' */
28+ def lmapEqualsFirstAndThenRmap [A , B , C ](fab : F [A , B ]): IsEq [F [(A , C ), B ]] =
29+ fab.lmap[(A , C )]({ case (a, _) => a }) <-> fab.first[C ].rmap[B ](_._1)
30+
31+ /** lmap snd == rmap snd . second' */
32+ def lmapEqualsSecondAndThenRmap [A , B , C ](fab : F [A , B ]): IsEq [F [(C , A ), B ]] =
33+ fab.lmap[(C , A )]({ case (_, b) => b }) <-> fab.second[C ].rmap[B ](_._2)
34+
35+ private def mapFirst [X , Y , Z ](f : X => Z )(cb : (X , Y )): (Z , Y ) = (f(cb._1), cb._2)
36+ private def mapSecond [X , Y , Z ](f : Y => Z )(cb : (X , Y )): (X , Z ) = (cb._1, f(cb._2))
37+
38+ /** lmap (second f) . first == rmap (second f) . first */
39+ def dinaturalityFirst [A , B , C , D ](fab : F [A , B ], f : C => D ): IsEq [F [(A , C ), (B , D )]] =
40+ fab.first[C ].rmap(mapSecond(f)) <-> fab.first[D ].lmap(mapSecond(f))
41+
42+ /** lmap (first f) . second == rmap (first f) . second */
43+ def dinaturalitySecond [A , B , C , D ](fab : F [A , B ], f : C => D ): IsEq [F [(C , A ), (D , B )]] =
44+ fab.second[C ].rmap(mapFirst(f)) <-> fab.second[D ].lmap(mapFirst(f))
45+
46+ private def assoc [A , B , C ]: (((A , B ), C )) => (A , (B , C )) = { case ((a, c), d) => (a, (c, d)) }
47+ private def unassoc [A , B , C ]: ((A , (B , C ))) => ((A , B ), C ) = { case (a, (c, d)) => ((a, c), d) }
48+
49+ /** first' . first' == dimap assoc unassoc . first' where
50+ * assoc ((a,b),c) = (a,(b,c))
51+ * unassoc (a,(b,c)) = ((a,b),c)
52+ */
53+ def firstFirstIsDimap [A , B , C , D ](fab : F [A , B ]): IsEq [F [((A , C ), D ), ((B , C ), D )]] =
54+ fab.first[C ].first[D ] <-> fab.first[(C , D )].dimap[((A , C ), D ), ((B , C ), D )](assoc)(unassoc)
55+
56+ /** second' . second' == dimap unassoc assoc . second' where
57+ * assoc ((a,b),c) = (a,(b,c))
58+ * unassoc (a,(b,c)) = ((a,b),c)
59+ */
60+ def secondSecondIsDimap [A , B , C , D ](fab : F [A , B ]): IsEq [F [(D , (C , A )), (D , (C , B ))]] =
61+ fab.second[C ].second[D ] <-> fab.second[(D , C )].dimap[(D , (C , A )), (D , (C , B ))](unassoc)(assoc)
2462}
2563
2664object StrongLaws {
0 commit comments