Skip to content

Commit 5dd0f89

Browse files
authored
Merge pull request #232 from lemastero/pro_optics_WIP
Profunctor optics + Yoneda encoding
2 parents f751e82 + 4c8b89e commit 5dd0f89

28 files changed

+832
-128
lines changed

ComputationalTrinitarianism.MD

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
## [Higher Category Theory](https://ncatlab.org/nlab/show/higher+category+theory)
1717

18-
* 2-Dimensional Categories - Niles Johnson, Donald Yau [(arXiv:2002.06055)](https://arxiv.org/pdf/2002.06055.pdf)
18+
* 2-Dimensional Categories - Niles Johnson, Donald Yau [(arxiv:2002.06055)](https://arxiv.org/abs/2002.06055), [(pdf)](https://arxiv.org/pdf/2002.06055.pdf)
1919
* Introduction to higher category theory - Tobias Dyckerhoff [(Lecture Notes, Problem Sets)](https://www.math.uni-hamburg.de/home/dyckerhoff/higher/index.html)
2020
* An Introduction to n-Categories - John C. Baez [(arXiv)](https://arxiv.org/abs/q-alg/9705009)
2121
* Basic Bicategories - Tom Leinster [(arXiv)](https://arxiv.org/abs/math/9810017)
@@ -145,6 +145,7 @@ This is very opinionated selection of authors that publish interesting papers ab
145145
* [Mauro Jaskelioff](https://dblp.uni-trier.de/pers/hd/j/Jaskelioff:Mauro)
146146
* [Johan Jeuring](https://dblp.uni-trier.de/pers/hd/j/Jeuring:Johan), [Utrecht University page](http://www.staff.science.uu.nl/~jeuri101/homepage/Publications/index.html)
147147
* [André Joyal](https://dblp.uni-trier.de/pers/hd/j/Joyal:Andr=eacute=), [arxiv](https://arxiv.org/search/math?query=Andr%C3%A9+Joyal&searchtype=author)
148+
* [Jacob Lurie](https://www.math.ias.edu/~lurie/)
148149
* [Jade Master](https://arxiv.org/search/math?searchtype=author&query=Master%2C+J)
149150
* [Lucius Gregory Meredith](https://dblp.org/pers/hd/m/Meredith:Lucius_Gregory)
150151
* [David Jaz Myers](http://davidjaz.com/), [arxiv](https://arxiv.org/search/math?searchtype=author&query=Myers%2C+D+J)
@@ -166,7 +167,7 @@ This is very opinionated selection of authors that publish interesting papers ab
166167
* [Wouter Swierstra](https://dblp.org/pers/hd/s/Swierstra:Wouter), [Utrecht University page](http://www.staff.science.uu.nl/~swier004/publications/)
167168
* [Tarmo Uustalu](http://cs.ioc.ee/~tarmo/papers/), [arXiv](https://arxiv.org/search/?query=Tarmo+Uustalu&searchtype=author&source=header)
168169
* [Christina Vasilakopoulou](https://thalis.math.upatras.gr/~cvasilak/), [arXiv](https://arxiv.org/search/math?searchtype=author&query=Vasilakopoulou%2C+C)
169-
* Philip Wadler [Monads, arrows, applicatives](http://homepages.inf.ed.ac.uk/wadler/topics/monads.html), [Parametricity](http://homepages.inf.ed.ac.uk/wadler/topics/parametricity.html)
170+
* [Philip Wadler](https://iohk.io/en/research/library/authors/philip-wadler/), [Monads, arrows, applicatives](http://homepages.inf.ed.ac.uk/wadler/topics/monads.html), [Parametricity](http://homepages.inf.ed.ac.uk/wadler/topics/parametricity.html)
170171

171172
## [Proof Theory](https://ncatlab.org/nlab/show/proof+theory)
172173

@@ -270,12 +271,13 @@ SCALING DOT TO SCALA - SOUNDNESS - Martin Odersky [(blog post)](https://www.scal
270271
* Monoidal categories in Python [oxford-quantum-group/discopy](https://github.com/oxford-quantum-group/discopy), paper: DisCoPy: Monoidal Categories in Python Giovanni de Felice, Alexis Toumi, Bob Coecke [arxiv 2005.02975](https://arxiv.org/abs/2005.02975)
271272
* Evan Patterson: Realizing Applied Category Theory in Julia [(video)](https://www.youtube.com/watch?v=7dmrDYQh4rc)
272273

273-
## Logic
274+
## (Constructive) Logic
274275

275276
* Substructural Logics - Carnegie Mellon University - Frank Pfenning [(course notes)](http://www.cs.cmu.edu/~fp/courses/15816-f16/schedule.html) [(assignments)](http://www.cs.cmu.edu/~fp/courses/15816-f16/assignments.html)
276277
* Constructive Logic - Carnegie Mellon University - Frank Pfenning [(course notes)](http://www.cs.cmu.edu/~fp/courses/15317-f17/schedule.html) [(assignments)](http://www.cs.cmu.edu/~fp/courses/15317-f17/assignments.html)
277278
* Linear Logic - Carnegie Mellon University - Frank Pfenning [(course)](http://www.cs.cmu.edu/~fp/courses/linear/schedule.html)
278279
* [Logical_Graphs](https://oeis.org/wiki/Logical_Graphs#Peirce.27s_law)
280+
* [Applied Logic course - Erik Palmgren](http://www2.math.uu.se/~palmgren/tillog/) (contains nice lecture notes, exercises in Coq)
279281

280282
## Nominal Techniques
281283

KanExtensions.MD

+48-16
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,72 @@ Construction that abstract over type constructor and allow to efficiently stack
77
In Category Theory
88

99
Yoneda Lemma states that:
10-
`[C,Set](C(a,-),F) ~ Fa`
11-
Set of natural transformations from `C` to `Set` of the Hom functor `C(a,-)` to Functor `F: C -> Set`
12-
is isomorphic to `Fa`
10+
`[C,Set](C(a,-),F) ~ F a`
11+
natural transformation between `Hom(a,-)` and functor `F: C -> Set` is isomorphic to value of Functor F on a `F a`.
1312

14-
It is possible to formulate Yoneda Lemma in terms of Ends, and we get Ninja Yoneda Lemma:
15-
∫ `Set(C(a,x),F(x)) ~ Fa`
13+
In Haskell this can be expressed as
14+
```haskell
15+
f a ~ forall x. (a -> x) -> f x
16+
````
1617

17-
That corresponds to:
18+
In Scala we ca define:
1819

19-
`def yoneda[R](cax: A => X, fx F[X]) ~ F[A]`
20+
```scala
21+
abstract class Yo[F[+_], A] {
22+
def runYo(): Reader[A, *] ~> F[*]
23+
}
24+
25+
type YonedaLemma[F[+_], A] = Yo[F, A] ~ F[A]
26+
def yonedaLemma[F[+_], A](implicit FF: Functor[F]): YonedaLemma[F, A] =
27+
new YonedaLemma[F, A] {
28+
def to: F[A] => Yo[F, A] = fa =>
29+
new Yo[F, A] {
30+
def runYo(): (A => *) ~> F =
31+
λ[(A => *) ~> F](atox => FF.map(fa)(atox))
32+
}
33+
34+
def from: Yo[F, A] => F[A] =
35+
(fa: Yo[F, A]) => {
36+
val raf: Reader[A, *] ~> F = fa.runYo()
37+
raf.apply(identity[A])
38+
}
39+
}
40+
```
41+
42+
where:
2043

2144
```scala
22-
trait Yoneda[F[_], A] {
23-
def run[R](f: A => R): F[R]
45+
type Reader[-R, +A] = R => A
46+
47+
trait ~[A, B] {
48+
def to: B => A
49+
def from: A => B
2450
}
2551
```
2652

27-
* we need Functor instance for F to create instance of Yoned for F
53+
In practice of FP following data structure is used:
54+
55+
```scala
56+
trait Yoneda[F[_], A] {
57+
def run[X](f: A => X): F[X]
58+
}
59+
```
60+
we need Functor instance for F to create instance of Yoneda for F
2861
```scala
2962
def liftYoneda[F[_], A](fa: F[A])(implicit FunctorF: Functor[F]): Yoneda[F, A] =
3063
new Yoneda[F, A] {
31-
def run[R2](f: A => R2): F[R2] = FunctorF.map(fa)(f)
64+
def run[X2](f: A => X2): F[X2] = FunctorF.map(fa)(f)
3265
}
3366
```
34-
35-
* we don't need the fact that F is a Functor to go back to F
67+
yet we don't need the fact that F is a Functor to go back to F
3668
```scala
3769
def lowerYoneda[F[_], A](y: Yoneda[F, A]): F[A] = y.run(identity[A])
3870
```
3971

40-
* we can define Functor instance, without any requirement on F:
72+
We can define Functor instance, without any requirement on F:
4173
```scala
42-
def yonedaFunctor[F[_]]: Functor[Yoneda[F, ?]] =
43-
new Functor[Yoneda[F, ?]] {
74+
def yonedaFunctor[F[_]]: Functor[Yoneda[F, *]] =
75+
new Functor[Yoneda[F, *]] {
4476
def map[A, B](fa: Yoneda[F, A])(f: A => B): Yoneda[F, B] =
4577
new Yoneda[F, B] {
4678
def run[C](f2: B => C): F[C] = fa.run(f andThen f2)

Profunctors.MD

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ trait StrongProfunctor[P[_, _]] extends Profunctor[P] {
153153
}
154154
```
155155

156-
* Laws [Haskell](https://hackage.haskell.org/package/profunctors/docs/Data-Profunctor-Strong.html) [Cats](https://github.com/typelevel/cats/blob/master/laws/src/main/scala/cats/laws/StrongLaws.scala)
156+
* Laws [Haskell](https://hackage.haskell.org/package/profunctors/docs/Data-Profunctor-Strong.html) [Scalaz 7](https://github.com/scalaz/scalaz/blob/series/7.3.x/core/src/main/scala/scalaz/Strong.scala#L16-L90) [Cats](https://github.com/typelevel/cats/blob/master/laws/src/main/scala/cats/laws/StrongLaws.scala)
157157
1) `first == dimap(swap, swap) andThen second`
158158
2) `lmap(_.1) == rmap(_.1) andThen first`
159159
3) `lmap(second f) andThen first == rmap(second f) andThen first`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package educational.category_theory
2+
3+
import cats.data.NonEmptyList
4+
5+
trait MonoidK[F[_]] {
6+
def empty[A]: F[A]
7+
def combine[A](lhs: F[A], rhs: F[A]): F[A]
8+
}
9+
10+
object MonoidK {
11+
val listMonoidK: MonoidK[List] = new MonoidK[List] {
12+
override def empty[A]: List[A] = Nil
13+
override def combine[A](lhs: List[A], rhs: List[A]): List[A] = lhs ++ rhs
14+
}
15+
16+
val vectorMonoidK: MonoidK[Vector] = new MonoidK[Vector] {
17+
override def empty[A]: Vector[A] = Vector.empty
18+
override def combine[A](lhs: Vector[A], rhs: Vector[A]): Vector[A] = lhs ++ rhs
19+
}
20+
21+
val optionMonoidK: MonoidK[Option] = new MonoidK[Option] {
22+
override def empty[A]: Option[A] = None
23+
24+
override def combine[A](lhs: Option[A], rhs: Option[A]): Option[A] = (lhs, rhs) match {
25+
case (None, r) => r
26+
case (l, _) => l
27+
}
28+
}
29+
}
30+
31+
trait Alternative[F[_]] extends MonoidK[F] with Applicative[F] {
32+
def some[A]: F[A] => F[NonEmptyList[A]] = v => map(v)(NonEmptyList.one)
33+
def many[A]: F[A] => F[List[A]] = v => map(v)(List(_))
34+
}
35+
//
36+
//object Alternative {
37+
// val vectorMonoidK: Alternative[Vector] = new Alternative[Vector] {
38+
// override def empty[A]: Vector[A] = Vector.empty
39+
// override def combine[A](lhs: Vector[A], rhs: Vector[A]): Vector[A] = lhs ++ rhs
40+
// override def pure[A](a: A): Vector[A] = Vector(a)
41+
// override def ap[A, B](ff: Vector[A => B])(fa: Vector[A]): Vector[B] = ???
42+
// }
43+
//
44+
// val optionMonoidK: Alternative[Option] = new Alternative[Option] {
45+
// override def empty[A]: Option[A] = None
46+
//
47+
// override def combine[A](lhs: Option[A], rhs: Option[A]): Option[A] = (lhs, rhs) match {
48+
// case (None, r) => r
49+
// case (l, _) => l
50+
// }
51+
// }
52+
//}

src/main/scala/educational/category_theory/Comonad.scala

+10
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,13 @@ extend(duplicate) \ |
4242
4343
*/
4444
}
45+
46+
object Comonad {
47+
implicit def TupleComonad[T]: Comonad[(T,*)] = new Comonad[(T, *)] {
48+
override def extract[A](wa: (T, A)): A = wa._2
49+
50+
override def duplicate[A](wa: (T, A)): (T, (T, A)) = (wa._1, wa)
51+
52+
override def map[A, B](wa: (T, A))(f: A => B): (T, B) = (wa._1, f(wa._2))
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package educational.category_theory
2+
3+
trait Invariant[F[_]] {
4+
def imap[A, B](fa: F[A])(f: A => B, g: B => A): F[B]
5+
}

src/main/scala/educational/category_theory/kan/DensitySimpleImpl.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ object DensitySimpleImpl {
4444
def comonadInstance[K[_]]: Comonad[Density[K, *]] =
4545
new Comonad[Density[K, *]] {
4646
def extract[A](w: Density[K, A]): A = w.f(w.fb)
47-
def duplicate[A](wa: Density[K, A]): Density[K, Density[K, A]] =
47+
override def duplicate[A](wa: Density[K, A]): Density[K, Density[K, A]] =
4848
Density[K, Density[K, A], wa.Z](
4949
kx => Density[K, A, wa.Z](wa.f, kx),
5050
wa.fb

src/main/scala/educational/category_theory/two/profunctor/closed/Closed.scala

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
package educational.category_theory.two.profunctor.closed
22

3-
import educational.category_theory.two.profunctor.Profunctor
4-
import educational.category_theory.two.profunctor.ProfunctorLaws
3+
import educational.category_theory.two.profunctor.{Profunctor, ProfunctorLaws}
54
import educational.category_theory.two.profunctor.ProfunctorInstance.Function1Profunctor
6-
import Function.const
7-
import Function.uncurried
8-
import Function.untupled
5+
6+
import scala.Function.{const, uncurried, untupled}
97

108
/**
119
* Closed Profunctor

src/main/scala/educational/collections/HeadNel.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ case class Nel[+A](head: A, tail: Nel[A])
2323
object NelInstances {
2424
val nelComonad: Comonad[Nel] = new Comonad[Nel] {
2525
def extract[A](w: Nel[A]): A = ???
26-
def duplicate[A](wa: Nel[A]): Nel[Nel[A]] = ???
26+
override def duplicate[A](wa: Nel[A]): Nel[Nel[A]] = ???
2727
def map[A, B](fa: Nel[A])(f: A => B): Nel[B] = ???
2828
}
2929
}

src/main/scala/educational/collections/RoseTree.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ object RoseTreeInstances {
88

99
val roseTreeComonad: Comonad[RoseTree] = new Comonad[RoseTree] {
1010
def extract[A](na: RoseTree[A]): A = na.tip
11-
def duplicate[A](na: RoseTree[A]): RoseTree[RoseTree[A]] =
11+
override def duplicate[A](na: RoseTree[A]): RoseTree[RoseTree[A]] =
1212
RoseTree(na, na.subTrees.map(duplicate))
1313
def map[A, B](na: RoseTree[A])(f: A => B): RoseTree[B] =
1414
RoseTree(f(na.tip), na.subTrees.map(s => map(s)(f)))

src/main/scala/educational/data/CoReader.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ object CoReaderInstances {
1313
def map[A, B](x: CoReader[R, A])(f: A => B): CoReader[R, B] =
1414
CoReader(f(x.extract), x.ask)
1515
def extract[A](w: CoReader[R, A]): A = w.extract
16-
def duplicate[A](wa: CoReader[R, A]): CoReader[R, CoReader[R, A]] =
16+
override def duplicate[A](wa: CoReader[R, A]): CoReader[R, CoReader[R, A]] =
1717
CoReader(wa, wa.ask)
1818
}
1919
}

src/main/scala/educational/data/Cofree.scala

+10-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ case class Cofree[A, F[_]](extract: A, sub: F[Cofree[A, F]])(implicit
1313
duplicate.map(f) // coKleisi composition
1414
}
1515

16+
object Cofree {
17+
18+
implicit def CofreeComonad[F[_]]: Comonad[Cofree[*, F]] = new Comonad[Cofree[*, F]] {
19+
override def extract[A](w: Cofree[A, F]): A = w.extract
20+
override def duplicate[A](wa: Cofree[A, F]): Cofree[Cofree[A, F], F] = wa.duplicate
21+
override def map[A, B](fa: Cofree[A, F])(f: A => B): Cofree[B, F] = fa.map(f)
22+
}
23+
}
24+
1625
case class CofreeList[A](extract: A, sub: List[CofreeList[A]])
1726

1827
object CofreeList {
@@ -22,7 +31,7 @@ object CofreeList {
2231
def map[A, B](ca: CofreeList[A])(f: A => B): CofreeList[B] =
2332
CofreeList(f(ca.extract), ca.sub.map(i => map(i)(f)))
2433
def extract[A](ca: CofreeList[A]): A = ca.extract
25-
def duplicate[A](ca: CofreeList[A]): CofreeList[CofreeList[A]] =
34+
override def duplicate[A](ca: CofreeList[A]): CofreeList[CofreeList[A]] =
2635
CofreeList(ca, ca.sub.map(duplicate))
2736
}
2837
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package educational.data
2+
3+
import educational.category_theory.Functor
4+
5+
// Matryoshka: https://github.com/precog/matryoshka/blob/master/core/shared/src/main/scala/matryoshka/data/Fix.scala
6+
// Y combinator on type level
7+
case class Fix[F[_]](unFix: F[Fix[F]])

src/main/scala/educational/data/Id.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ object IdInstances {
88
val idComonad: Comonad[Id] = new Comonad[Id] {
99
def map[A, B](x: Id[A])(f: A => B): Id[B] = Id(f(x.value))
1010
def extract[A](w: Id[A]): A = w.value
11-
def duplicate[A](wa: Id[A]): Id[Id[A]] = Id(wa)
11+
override def duplicate[A](wa: Id[A]): Id[Id[A]] = Id(wa)
1212
}
1313
}
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package educational.data
2+
3+
trait Nu[F[_]] {
4+
type A
5+
val a: A
6+
val unNu: A => F[A]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package educational.optics
2+
3+
trait ~[A,B] {
4+
def to: B => A
5+
def from: A => B
6+
}
7+
8+
object Iso {
9+
type Equivalence[A, B] = ~[A, B]
10+
type Bijection[A, B] = ~[A, B]
11+
}
12+
13+
case class Iso[S,A](from: S => A, to: A => S) { self => // Adapter
14+
def modifyB(f: A => A): S => S =
15+
(from andThen f) andThen to
16+
// def andThen[B](other: Iso[A,B]): Iso[S,B] = Iso[S,B](
17+
// self.from andThen other.from,
18+
//
19+
// )
20+
}
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package educational.optics
2+
3+
case class Lens[+A,-B,-S,+T](
4+
view: S => A,
5+
update: (B,S) => T
6+
)
7+
8+
object LensExamples {
9+
10+
def tupleFoucsFirst[A,B,C]: Lens[A, B, (A,C), (B,C)] = {
11+
def getFst: ((A,C)) => A = { case (a, _) => a }
12+
def overrideFst: (B,(A,C)) => (B,C) = { case (b, (_,c)) => (b,c) }
13+
Lens[A, B, (A,C), (B,C)](getFst, overrideFst)
14+
}
15+
16+
def tupleFoucsSecond[A,B,C]: Lens[A, B, (A,C), (B,C)] = {
17+
def getFst: ((A,C)) => A = { case (a, _) => a }
18+
def overrideFst: (B, (A,C)) => (B,C) = { case (b, (_, c)) => (b, c) }
19+
Lens[A, B, (A,C), (B,C)](getFst, overrideFst)
20+
}
21+
22+
// monomorphic - types have to be the same for A,B and S,T
23+
val signNonNegative: Lens[Boolean, Boolean, Int, Int] = {
24+
def isNonNegative: Int => Boolean = _ >= 0
25+
def asNonNegative: (Boolean,Int) => Int = { case(b,n) =>
26+
if(b) Math.abs(n)
27+
else -Math.abs(n)
28+
}
29+
30+
Lens[Boolean, Boolean, Int, Int](isNonNegative, asNonNegative)
31+
}
32+
33+
// Nat and isOdd would work
34+
// Nat and isPrime would be tricky (enforcing property could be hard)
35+
36+
// compsing lens
37+
// def tupleInnerFirst[A,B,C,D]: Lens[A, B, ((A,C),D), ((B,C),D)] = {
38+
// def overrideFst: (B,(A,C)) => (B,C) = { case (b, (_,c)) => (b,c) }
39+
// Lens[A, B, ((A,C),D), ((B,C),D)](tupleFoucsFirst.view andThen tupleFoucsFirst.view, overrideFst)
40+
// }
41+
42+
// TODO finish + check if we use Option instead of Either if that helps?
43+
}

0 commit comments

Comments
 (0)