SlideShare una empresa de Scribd logo
1 de 58
Descargar para leer sin conexión
Contravariant Functors in Scala
prepending wagons to the train like a CT pro
Piotr Paradziński
ScalaC03.03.2020
1
● PR’s to Scalaz 7 / Cats
○ Scalaz7 github.com/scalaz/scalaz/pull/2020 Day convolution (0,5 year fight translate from Haskell)
○ Scalaz7 github.com/scalaz/scalaz/pull/2028 add Strong Profunctor laws
○ Scalaz7 github.com/scalaz/scalaz/pull/2029 Density comonad
○ Cats github.com/typelevel/cats/pull/2640 replace Strong Profunctor laws (based on CT)
● type_classopedia - wiki about abstractions from CT github.com/lemastero/scala_typeclassopedia
●
● Small fix in (broken links this is how you start!, docs):
○ Haskell Profunctors github.com/ekmett/profunctors/pull/65 github.com/ekmett/profunctors/pull/66
○ Sclaz ZIO github.com/scalaz/scalaz-zio/pulls?utf8=%E2%9C%93&q=+author%3Alemastero SclaC Hackaton
○ yallop/effects-bibliography github.com/yallop/effects-bibliography/pulls?utf8=✓&q=+author%3Alemastero
○ steshaw.org/plt/ (github.com/steshaw/plt/pulls?utf8=✓&q=+author%3Alemastero)
○ cohomolo-gy/haskell-resources github.com/cohomolo-gy/haskell-resources/pull/3
○ passy/awesome-recurion-schemas github.com/passy/awesome-recursion-schemes/pull/22
○ Agda https://github.com/agda/agda/pull/3751
○ awesome-provable https://github.com/awesomo4000/awesome-provable/pull/1
○ Andrej Baure HoTT lectures: https://github.com/andrejbauer/homotopy-type-theory-course/pull/3
○ Cubical TT course by groupoid https://github.com/groupoid/groupoid.space/pull/20
○ statebox/awesome-applied-CT https://github.com/statebox/awesome-applied-ct/issues?q=author%3Alemastero
INPUT => OUTPUT
3
INPUT => OUTPUT
monix.Task[A], Future[A]
Functor[F], Monad[F],
Comonad[F],
Reader
4
INPUT => OUTPUT
monix.Task[A], Future[A]
Functor[F], Monad[F],
Comonad[F],
Reader
Why we focus only on output?
5
INPUT => OUTPUT
Think
backwards!
6
Contravariant Functors
7
Contravariant Functors
8
Prepend wagos to end Append new Locomotive to begin
(at the end) INPUT (to beginning) OUTPUT
Predicate - checks property of type A
case class Predicate[A](fun: A => Boolean)
9
Predicate - complicated one ;)
case class Predicate[A](fun: A => Boolean)
val hasEnoughLength: Predicate[Int] = Predicate(a => a > 3)
10
Can we use length to create Predicate[String]?
case class Predicate[A](fun: A => Boolean)
val hasEnoughLength: Predicate[Int] = Predicate(a => a > 3)
def len(s: String): Int = s.length
val isValidCode: Predicate[String] = ???
11
Predicate - can we map (define Functor)?
case class Predicate[A](fun: A => Boolean)
import cats.Functor
val predicateFuncor: Functor[Predicate] = new Functor[Predicate] {
def map[A, B](fa: Predicate[A])(f: A => B): Predicate[B] = ???
}
12
Predicate - but we can prepend!
case class Predicate[A](fun: A => Boolean)
val hasEnoughLength: Predicate[Int] = Predicate(a => a > 3)
def len(s: String): Int = s.length
val isValidCode: Predicate[String] =
Predicate[String](len andThen hasEnoughLength.fun)
13
case class Predicate[A](fun: A => Boolean)
def contramap[A, B](pred: Predicate[A])(fba: B => A): Predicate[B] =
Predicate[B](fba andThen pred.fun)
Predicate - generalize prepend
14
Example2 - Show
trait Show[F] {
def show(f: F): String
}
Scalaz github.com/scalaz/scalaz/blob/series/7.3.x/core/src/main/scala/scalaz/Show.scala#L51-L53
15
Example2 - Can we reuse existing Show?
trait Show[A] {
def show(a: A): String
}
case class Processor(name: String)
case class Multicore(name: String, coreCount: Int)
val sp: Show[Processor] = new Show[Processor] {
override def show(a: Processor): String = s"Processor ${a.name}"
}
def asProcessor(mc: Multicore): Processor = Processor(s"${mc.coreCount} x ${mc.name}")
16
Example2 - Can we define Functor for Show?
trait Show[A] {
def show(a: A): String
}
val showFunctor: Functor[Show] = new Functor[Show] {
override def map[A, B](fa: Show[A])(f: A => B): Show[B] = ???
}
17
Example2 - no! but we can prepend
trait Show[A] {
def show(a: A): String
}
def contramap[A, B](fa: Show[A])(f: B => A): Show[B] = new Show[B] {
override def show(a: B): String = fa.show(f(a))
}
18
Common pattern - prepend to input 1/3
trait Show[A] {
def show(a: A): String
}
def prepend[A, B](fa: Show[A])(f: B => A): Show[B] = new Show[B] {
override def show(a: B): String = fa.show(f(a))
}
19
Common pattern - prepend to input 2/3
case class Predicate[A](fun: A => Boolean)
def prepend[A, B](pred: Predicate[A])(fba: B => A): Predicate[B] =
Predicate[B](fba andThen pred.fun)
20
Common pattern - prepend to input Contravariant
trait InputPrepender[F[_]] {
def prepend[A, B] (fa: F[A])(f: B => A): F[B]
}
21
Mathematicians and names :)
trait Contravariant[F[_]] {
def contramap[A, B] (fa: F[A])(f: B => A): F[B]
}
22
Contravariant - like a Functor but flip!
trait Functor[F[_]] {
def map[A, B] (fa: F[A]) (f: A => B): F[B]
}
trait Contravariant[F[_]] {
def contramap[A, B] (fa: F[A]) (f: B => A): F[B]
}
23
Contravariant Functor - input + ability to prepend
Functor is “full of” A’s (container A, function producing A)
F[A] we can map A => B and we get F[B]
F[A] we can contramap B => A and we get F[B]
Contravariant “needs” A (index of container, function
consuming A)
24
Contravariant Functor
25
Prepend Append
contramap map
to INPUT to OUTPUT
Exercises - Contravariant for scala.math.Equiv
trait Equiv[T] {
def equiv(x: T, y: T): Boolean
}
val EquivContra: Contravariant[Equiv] = new Contravariant[Equiv] {
override def contramap[A, B](fa: Equiv[A])(f: B => A): Equiv[B] = ???
}
Much more:
https://github.com/lemastero/contravariant_profunctor_exercises/blob/master/src/main/scala/contra_pro/Exercise1_Contravariant.
scala
26
Contravariant - example Function1
def function1Contravariant[R]: Contravariant[? => R] =
new Contravariant[? => R] {
def contramap[A, B](r: A => R)(f: B => A) = r compose f
}
27
Contravariant - example Function1
def function1Contravariant[R]: Contravariant[? => R] =
new Contravariant[? => R] {
def contramap[A, B](r: A => R)(f: B => A) = r compose f
}
Glorified compose of Function1 !!!
28
Contravariant - example Reader (1)
case class Reader[C, V](run: C => V)
29
Contravariant - example Reader - Functor
case class Reader[C, V](run: C => V)
def readerFunctor[C] = new Functor[Reader[C,?]] {
def map[A, B](x: Reader[C, A])(f: A => B): Reader[C, B] =
Reader(x.run andThen f)
}
30
Contravariant - example Reader - Monad
case class Reader[C, V](run: C => V)
def readerMonad[C] = new Monad[Reader[C, ?]] {
def map[A, B](x: Reader[C, A])(f: A => B): Reader[C, B] =
Reader(x.run andThen f)
def pure[A](a: A): Reader[C, A] =
new Reader(_ => a)
def flatMap[A, B](ma: Reader[C, A])(f: A => Reader[C, B]) = ???
}
31
Contravariant - example Reader - Contravariant
case class Reader[C, V](run: C => V)
def readerContra[V] = new Contravariant[Reader[?, V]] {
def contramap[A, B](fa: Reader[A, V])(f: B => A):
Reader[B, V] = Reader(f andThen fa.run)
}
32
Functor laws
fmap id = id
fmap f . fmap g = fmap (f . g)
Contravariant laws
contramap id = id
contramap f . contramap g = contramap (g . f)
Contravariant - laws in Haskell
33
Contravariant - laws in Scala
34
Cats:
github.com/typelevel/cats/blob/master/laws/src/main/scala/cats/laws/ContravariantLaws.scala
Scalaz 7:
github.com/scalaz/scalaz/blob/series/7.3.x/core/src/main/scala/scalaz/Contravariant.scala#L59-L68
scala_typeclassopedia:
github.com/lemastero/scala_typeclassopedia#contravariant-contravariant-functor
Contravariant - laws in Scala
35
Contravariant - FunctionN parameters all but last
trait Function2[-T1, -T2, +R]{
def apply(v1: T1, v2: T2): R
}
trait Function3[-T1, -T2, -T3, +R]{
def apply(v1: T1, v2: T2, v3: T3): R
}
//...
All parameters are in negative position, co we could define Contravariant
instance for it.
(Or even BiContravariant, TriContravariant, ... if they existed :)
36
Contravariant * Contravariant = Covariant
Compose contravariant functors:
https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/Contravariant.scala#L11-L15
Input of your input is not my input
But it’s input is ...
https://github.com/lemastero/scala_typeclassopedia/blob/master/src/main/scala/contravariant/HoFStructure.scala
37
Contravariant Functors everywhere
● Kafka producer
● HTTP endpoints
● DB Repository
● S3 client
● ...
38
Contravariant Functors everywhere but why?
We don’t want to map … and change HttpApi[Json] into HttpApi[Ints]
We might want to:
● provide part of configuration
● change config file path to parsed case class with configuration
● set execution context for all operations
● provide dependency like AvroKafkaDeserializer and schema registry config
(clients don’t have to worry about it)
● add defaults and require only Option[Config]
● ...
39
Contravariant - examples in open source libs
Encoder in Scodec:
github.com/scodec/scodec/blob/series/1.11.x/shared/src/main/scala/scodec/Encoder.scala#L40-L47
Schedule/ZSink/ZQueue in ZIO (contramap, provideSome):
https://github.com/zio/zio/search?q=contramap&unscoped_q=contramap
Logger
https://github.com/zio/zio-logging/issues/7
JSON Encoder in Circe
https://github.com/circe/circe/blob/master/modules/core/shared/src/main/scala/io/circe/Encoder.scala#L53-L55
40
https://gitlab.haskell.org/ghc/ghc/issues/14767
https://github.com/ghc/ghc/blob/master/libraries/base/changelog.md#41200-21-september-2018
Contravariant part of Haskell GHC 8.6.1 in 2018
41
Contravariant - discrimination sort
youtube.com/watch?v=cB8DapKQz-I
Sorting in linear time
Edward Kmett in Haskell
In Scala?
42
Divide
(Contravariant Semigroupal - in Cats)
43
case class Serializer[A](run: A => Array[Byte])
val strSerial = Serializer[String](_.getBytes)
val intSerial = Serializer[Int](_.toString.getBytes)
GOTO Github:
https://github.com/lemastero/contravariant_profunctor_exercises/blob/master/src/test/scala/contra_pro/DivideSpec.scala
Divide (1) - Serialization
44
val fragmentSerial = Serializer[Fragment] { frag =>
val a1 = strSerial.run(frag.name)
val a2 = intSerial.run(frag.size)
a1 ++ a2
}
val serialized = fragmentSerial.run(Fragment("Area", 52))
new String(serialized ) mustBe "Area52"
Divide (2) - How to combine serializers?
45
trait Divide[F[_]] extends Contravariant[F] {
def divide[A,B,C](f: A => (B,C), fb: F[B], fc: F[C]): F[A]
}
Divide (3) - abstraction
46
val fragmentDivide: Divide[Serializer] = new Divide[Serializer] {
def divide2[A1, A2, Z](s1: => Serializer[ A1], s2: => Serializer[ A2])(f: Z
=> (A1, A2)): Serializer[ Z] = Serializer{ frag =>
val (a1,a2) = f(frag)
s1.run(a1) ++ s2.run(a2)
}
}
Divide (4)
47
val fragAsTuple: Fragment => (String, Int) =
frag => (frag.name, frag.size)
val fragSerial: Serializer[Fragment] =
Divide[Serializer].divide(strSerial, intSerial)(fragAsTuple)
Divide (5)
48
val fragAsTuple: Fragment => (String, Int) =
frag => (frag.name, frag.size)
val fragSerial: Serializer[Fragment] =
Divide[Serializer].divide(strSerial, intSerial)(fragAsTuple)
val serialized = fragSerial.run(Fragment("Area", 52))
new String(serialized ) mustBe "Area52"
Divide - Run
49
https://github.com/lemastero/scala_typeclassopedia/blob/master/Contravariant.MD
#divide-contravariant-apply
Divide - Laws & derived methods
50
Define full laws for Divide as in Haskell
hackage.haskell.org/package/contravariant/docs/Data-Functor-Contravariant-Divisible.html#g:4
Not simplified as in Scalaz and Cats!
Contravariant - Divide - Challenge
51
Big Picture
52
Functor - Signature
def map[A,B](fa: F[A])(f: A => B): F[B] Functor
53
Apply - Signature
def map[A,B](fa: F[A])(f: A => B): F[B] Functor
def ap[A,B](ff: F[A => B])(fa: F[A]): F[B] Apply
54
Applicative - Signature
def map[A,B](fa: F[A])(f: A => B): F[B] Functor
def ap[A,B](ff: F[A => B])(fa: F[A]): F[B] Apply
def pure[A](value: A): F[A] Applicative
55
Contravariant Functors - arrows reversed
//def map (F[A], A => B): F[B] Functor
def contramap (F[A], B => A): F[B] Contravariant (Contravariant Functor)
//def map2 ((A,B) => Z, F[A], F[B]): F[Z] Apply (not ap!)
def divide (Z => (A,B), F[A], F[B]): F[Z] Divide (Contravariant Apply)
//def pure: ( () => A ) => F[A] Applicative
def conquer: ( A => () ) => F[A] Divisible (Contravariant Applicative)
56
Good general theory does not search for the maximum
generality, but for the right generality.
Saunders Mac Lane
Choose the right level of abstraction, to see the
problem more clearly
Eugenia Cheng, Category in Life
https://www.youtube.com/watch?v=ho7oagHeqNc
Thank you :)
57
Thank you :)
58

Más contenido relacionado

La actualidad más candente

The Next Great Functional Programming Language
The Next Great Functional Programming LanguageThe Next Great Functional Programming Language
The Next Great Functional Programming LanguageJohn De Goes
 
Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1Hang Zhao
 
Advance LISP (Artificial Intelligence)
Advance LISP (Artificial Intelligence) Advance LISP (Artificial Intelligence)
Advance LISP (Artificial Intelligence) wahab khan
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them AllJohn De Goes
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2Hang Zhao
 
Why functional programming and category theory strongly matters
Why functional programming and category theory strongly mattersWhy functional programming and category theory strongly matters
Why functional programming and category theory strongly mattersPiotr Paradziński
 
Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Philip Schwarz
 
Abstracting over the Monad yielded by a for comprehension and its generators
Abstracting over the Monad yielded by a for comprehension and its generatorsAbstracting over the Monad yielded by a for comprehension and its generators
Abstracting over the Monad yielded by a for comprehension and its generatorsPhilip Schwarz
 
Fp in scala with adts
Fp in scala with adtsFp in scala with adts
Fp in scala with adtsHang Zhao
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsPhilip Schwarz
 
Introduction To Lisp
Introduction To LispIntroduction To Lisp
Introduction To Lispkyleburton
 
Core csharp and net quick reference
Core csharp and net quick referenceCore csharp and net quick reference
Core csharp and net quick referenceilesh raval
 
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...Philip Schwarz
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class PatternsJohn De Goes
 
Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Philip Schwarz
 

La actualidad más candente (19)

The Next Great Functional Programming Language
The Next Great Functional Programming LanguageThe Next Great Functional Programming Language
The Next Great Functional Programming Language
 
MTL Versus Free
MTL Versus FreeMTL Versus Free
MTL Versus Free
 
Idiomatic C++
Idiomatic C++Idiomatic C++
Idiomatic C++
 
Fp in scala part 1
Fp in scala part 1Fp in scala part 1
Fp in scala part 1
 
Advance LISP (Artificial Intelligence)
Advance LISP (Artificial Intelligence) Advance LISP (Artificial Intelligence)
Advance LISP (Artificial Intelligence)
 
One Monad to Rule Them All
One Monad to Rule Them AllOne Monad to Rule Them All
One Monad to Rule Them All
 
Fp in scala with adts part 2
Fp in scala with adts part 2Fp in scala with adts part 2
Fp in scala with adts part 2
 
Why functional programming and category theory strongly matters
Why functional programming and category theory strongly mattersWhy functional programming and category theory strongly matters
Why functional programming and category theory strongly matters
 
Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2
 
Functors
FunctorsFunctors
Functors
 
Abstracting over the Monad yielded by a for comprehension and its generators
Abstracting over the Monad yielded by a for comprehension and its generatorsAbstracting over the Monad yielded by a for comprehension and its generators
Abstracting over the Monad yielded by a for comprehension and its generators
 
Fp in scala with adts
Fp in scala with adtsFp in scala with adts
Fp in scala with adts
 
Monoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and CatsMonoids - Part 1 - with examples using Scalaz and Cats
Monoids - Part 1 - with examples using Scalaz and Cats
 
Introduction To Lisp
Introduction To LispIntroduction To Lisp
Introduction To Lisp
 
Core csharp and net quick reference
Core csharp and net quick referenceCore csharp and net quick reference
Core csharp and net quick reference
 
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
 
Monad Fact #2
Monad Fact #2Monad Fact #2
Monad Fact #2
 
First-Class Patterns
First-Class PatternsFirst-Class Patterns
First-Class Patterns
 
Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'Simple IO Monad in 'Functional Programming in Scala'
Simple IO Monad in 'Functional Programming in Scala'
 

Similar a Contravariant functors in scala

Big picture of category theory in scala with deep dive into contravariant and...
Big picture of category theory in scala with deep dive into contravariant and...Big picture of category theory in scala with deep dive into contravariant and...
Big picture of category theory in scala with deep dive into contravariant and...Scalac
 
Shape Safety in Tensor Programming is Easy for a Theorem Prover -SBTB 2021
Shape Safety in Tensor Programming is Easy for a Theorem Prover -SBTB 2021Shape Safety in Tensor Programming is Easy for a Theorem Prover -SBTB 2021
Shape Safety in Tensor Programming is Easy for a Theorem Prover -SBTB 2021Peng Cheng
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadOliver Daff
 
Functional Programming Concepts for Imperative Programmers
Functional Programming Concepts for Imperative ProgrammersFunctional Programming Concepts for Imperative Programmers
Functional Programming Concepts for Imperative ProgrammersChris
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondMario Fusco
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scalapramode_ce
 
Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009Martin Odersky
 
Scala is java8.next()
Scala is java8.next()Scala is java8.next()
Scala is java8.next()daewon jeong
 
Functional programming-advantages
Functional programming-advantagesFunctional programming-advantages
Functional programming-advantagesSergei Winitzki
 
Kotlin advanced - language reference for android developers
Kotlin advanced - language reference for android developersKotlin advanced - language reference for android developers
Kotlin advanced - language reference for android developersBartosz Kosarzycki
 
Kotlin Advanced - language reference for Android developers
Kotlin Advanced - language reference for Android developers Kotlin Advanced - language reference for Android developers
Kotlin Advanced - language reference for Android developers STX Next
 
Столпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай МозговойСтолпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай МозговойSigma Software
 
Rewriting Java In Scala
Rewriting Java In ScalaRewriting Java In Scala
Rewriting Java In ScalaSkills Matter
 
Scala Collections : Java 8 on Steroids
Scala Collections : Java 8 on SteroidsScala Collections : Java 8 on Steroids
Scala Collections : Java 8 on SteroidsFrançois Garillot
 
Programming Android Application in Scala.
Programming Android Application in Scala.Programming Android Application in Scala.
Programming Android Application in Scala.Brian Hsu
 

Similar a Contravariant functors in scala (20)

Big picture of category theory in scala with deep dive into contravariant and...
Big picture of category theory in scala with deep dive into contravariant and...Big picture of category theory in scala with deep dive into contravariant and...
Big picture of category theory in scala with deep dive into contravariant and...
 
Shape Safety in Tensor Programming is Easy for a Theorem Prover -SBTB 2021
Shape Safety in Tensor Programming is Easy for a Theorem Prover -SBTB 2021Shape Safety in Tensor Programming is Easy for a Theorem Prover -SBTB 2021
Shape Safety in Tensor Programming is Easy for a Theorem Prover -SBTB 2021
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And Monad
 
Java 8
Java 8Java 8
Java 8
 
Functional Programming Concepts for Imperative Programmers
Functional Programming Concepts for Imperative ProgrammersFunctional Programming Concepts for Imperative Programmers
Functional Programming Concepts for Imperative Programmers
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyond
 
Lecture 3
Lecture 3Lecture 3
Lecture 3
 
Introduction to Functional Programming with Scala
Introduction to Functional Programming with ScalaIntroduction to Functional Programming with Scala
Introduction to Functional Programming with Scala
 
Scala in a nutshell by venkat
Scala in a nutshell by venkatScala in a nutshell by venkat
Scala in a nutshell by venkat
 
Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009
 
Spark workshop
Spark workshopSpark workshop
Spark workshop
 
Scala is java8.next()
Scala is java8.next()Scala is java8.next()
Scala is java8.next()
 
Functional programming-advantages
Functional programming-advantagesFunctional programming-advantages
Functional programming-advantages
 
Scala @ TomTom
Scala @ TomTomScala @ TomTom
Scala @ TomTom
 
Kotlin advanced - language reference for android developers
Kotlin advanced - language reference for android developersKotlin advanced - language reference for android developers
Kotlin advanced - language reference for android developers
 
Kotlin Advanced - language reference for Android developers
Kotlin Advanced - language reference for Android developers Kotlin Advanced - language reference for Android developers
Kotlin Advanced - language reference for Android developers
 
Столпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай МозговойСтолпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай Мозговой
 
Rewriting Java In Scala
Rewriting Java In ScalaRewriting Java In Scala
Rewriting Java In Scala
 
Scala Collections : Java 8 on Steroids
Scala Collections : Java 8 on SteroidsScala Collections : Java 8 on Steroids
Scala Collections : Java 8 on Steroids
 
Programming Android Application in Scala.
Programming Android Application in Scala.Programming Android Application in Scala.
Programming Android Application in Scala.
 

Último

JS-Experts - Cybersecurity for Generative AI
JS-Experts - Cybersecurity for Generative AIJS-Experts - Cybersecurity for Generative AI
JS-Experts - Cybersecurity for Generative AIIvo Andreev
 
Sales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales CoverageSales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales CoverageDista
 
Top Software Development Trends in 2024
Top Software Development Trends in  2024Top Software Development Trends in  2024
Top Software Development Trends in 2024Mind IT Systems
 
Your Vision, Our Expertise: TECUNIQUE's Tailored Software Teams
Your Vision, Our Expertise: TECUNIQUE's Tailored Software TeamsYour Vision, Our Expertise: TECUNIQUE's Tailored Software Teams
Your Vision, Our Expertise: TECUNIQUE's Tailored Software TeamsJaydeep Chhasatia
 
Kawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in TrivandrumKawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in TrivandrumKawika Technologies
 
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...Jaydeep Chhasatia
 
IA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG timeIA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG timeNeo4j
 
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine HarmonyLeveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmonyelliciumsolutionspun
 
online pdf editor software solutions.pdf
online pdf editor software solutions.pdfonline pdf editor software solutions.pdf
online pdf editor software solutions.pdfMeon Technology
 
Enterprise Document Management System - Qualityze Inc
Enterprise Document Management System - Qualityze IncEnterprise Document Management System - Qualityze Inc
Enterprise Document Management System - Qualityze Incrobinwilliams8624
 
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdf
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdfARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdf
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdfTobias Schneck
 
OpenChain Webinar: Universal CVSS Calculator
OpenChain Webinar: Universal CVSS CalculatorOpenChain Webinar: Universal CVSS Calculator
OpenChain Webinar: Universal CVSS CalculatorShane Coughlan
 
ERP For Electrical and Electronics manufecturing.pptx
ERP For Electrical and Electronics manufecturing.pptxERP For Electrical and Electronics manufecturing.pptx
ERP For Electrical and Electronics manufecturing.pptxAutus Cyber Tech
 
Webinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.pptWebinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.pptkinjal48
 
eAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspectionseAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspectionsNirav Modi
 
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...OnePlan Solutions
 
Watermarking in Source Code: Applications and Security Challenges
Watermarking in Source Code: Applications and Security ChallengesWatermarking in Source Code: Applications and Security Challenges
Watermarking in Source Code: Applications and Security ChallengesShyamsundar Das
 
Generative AI for Cybersecurity - EC-Council
Generative AI for Cybersecurity - EC-CouncilGenerative AI for Cybersecurity - EC-Council
Generative AI for Cybersecurity - EC-CouncilVICTOR MAESTRE RAMIREZ
 
How Does the Epitome of Spyware Differ from Other Malicious Software?
How Does the Epitome of Spyware Differ from Other Malicious Software?How Does the Epitome of Spyware Differ from Other Malicious Software?
How Does the Epitome of Spyware Differ from Other Malicious Software?AmeliaSmith90
 

Último (20)

JS-Experts - Cybersecurity for Generative AI
JS-Experts - Cybersecurity for Generative AIJS-Experts - Cybersecurity for Generative AI
JS-Experts - Cybersecurity for Generative AI
 
Sales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales CoverageSales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales Coverage
 
Top Software Development Trends in 2024
Top Software Development Trends in  2024Top Software Development Trends in  2024
Top Software Development Trends in 2024
 
Your Vision, Our Expertise: TECUNIQUE's Tailored Software Teams
Your Vision, Our Expertise: TECUNIQUE's Tailored Software TeamsYour Vision, Our Expertise: TECUNIQUE's Tailored Software Teams
Your Vision, Our Expertise: TECUNIQUE's Tailored Software Teams
 
Kawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in TrivandrumKawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in Trivandrum
 
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...
 
IA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG timeIA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG time
 
Salesforce AI Associate Certification.pptx
Salesforce AI Associate Certification.pptxSalesforce AI Associate Certification.pptx
Salesforce AI Associate Certification.pptx
 
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine HarmonyLeveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
 
online pdf editor software solutions.pdf
online pdf editor software solutions.pdfonline pdf editor software solutions.pdf
online pdf editor software solutions.pdf
 
Enterprise Document Management System - Qualityze Inc
Enterprise Document Management System - Qualityze IncEnterprise Document Management System - Qualityze Inc
Enterprise Document Management System - Qualityze Inc
 
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdf
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdfARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdf
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdf
 
OpenChain Webinar: Universal CVSS Calculator
OpenChain Webinar: Universal CVSS CalculatorOpenChain Webinar: Universal CVSS Calculator
OpenChain Webinar: Universal CVSS Calculator
 
ERP For Electrical and Electronics manufecturing.pptx
ERP For Electrical and Electronics manufecturing.pptxERP For Electrical and Electronics manufecturing.pptx
ERP For Electrical and Electronics manufecturing.pptx
 
Webinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.pptWebinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.ppt
 
eAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspectionseAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspections
 
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
 
Watermarking in Source Code: Applications and Security Challenges
Watermarking in Source Code: Applications and Security ChallengesWatermarking in Source Code: Applications and Security Challenges
Watermarking in Source Code: Applications and Security Challenges
 
Generative AI for Cybersecurity - EC-Council
Generative AI for Cybersecurity - EC-CouncilGenerative AI for Cybersecurity - EC-Council
Generative AI for Cybersecurity - EC-Council
 
How Does the Epitome of Spyware Differ from Other Malicious Software?
How Does the Epitome of Spyware Differ from Other Malicious Software?How Does the Epitome of Spyware Differ from Other Malicious Software?
How Does the Epitome of Spyware Differ from Other Malicious Software?
 

Contravariant functors in scala

  • 1. Contravariant Functors in Scala prepending wagons to the train like a CT pro Piotr Paradziński ScalaC03.03.2020 1
  • 2. ● PR’s to Scalaz 7 / Cats ○ Scalaz7 github.com/scalaz/scalaz/pull/2020 Day convolution (0,5 year fight translate from Haskell) ○ Scalaz7 github.com/scalaz/scalaz/pull/2028 add Strong Profunctor laws ○ Scalaz7 github.com/scalaz/scalaz/pull/2029 Density comonad ○ Cats github.com/typelevel/cats/pull/2640 replace Strong Profunctor laws (based on CT) ● type_classopedia - wiki about abstractions from CT github.com/lemastero/scala_typeclassopedia ● ● Small fix in (broken links this is how you start!, docs): ○ Haskell Profunctors github.com/ekmett/profunctors/pull/65 github.com/ekmett/profunctors/pull/66 ○ Sclaz ZIO github.com/scalaz/scalaz-zio/pulls?utf8=%E2%9C%93&q=+author%3Alemastero SclaC Hackaton ○ yallop/effects-bibliography github.com/yallop/effects-bibliography/pulls?utf8=✓&q=+author%3Alemastero ○ steshaw.org/plt/ (github.com/steshaw/plt/pulls?utf8=✓&q=+author%3Alemastero) ○ cohomolo-gy/haskell-resources github.com/cohomolo-gy/haskell-resources/pull/3 ○ passy/awesome-recurion-schemas github.com/passy/awesome-recursion-schemes/pull/22 ○ Agda https://github.com/agda/agda/pull/3751 ○ awesome-provable https://github.com/awesomo4000/awesome-provable/pull/1 ○ Andrej Baure HoTT lectures: https://github.com/andrejbauer/homotopy-type-theory-course/pull/3 ○ Cubical TT course by groupoid https://github.com/groupoid/groupoid.space/pull/20 ○ statebox/awesome-applied-CT https://github.com/statebox/awesome-applied-ct/issues?q=author%3Alemastero
  • 4. INPUT => OUTPUT monix.Task[A], Future[A] Functor[F], Monad[F], Comonad[F], Reader 4
  • 5. INPUT => OUTPUT monix.Task[A], Future[A] Functor[F], Monad[F], Comonad[F], Reader Why we focus only on output? 5
  • 8. Contravariant Functors 8 Prepend wagos to end Append new Locomotive to begin (at the end) INPUT (to beginning) OUTPUT
  • 9. Predicate - checks property of type A case class Predicate[A](fun: A => Boolean) 9
  • 10. Predicate - complicated one ;) case class Predicate[A](fun: A => Boolean) val hasEnoughLength: Predicate[Int] = Predicate(a => a > 3) 10
  • 11. Can we use length to create Predicate[String]? case class Predicate[A](fun: A => Boolean) val hasEnoughLength: Predicate[Int] = Predicate(a => a > 3) def len(s: String): Int = s.length val isValidCode: Predicate[String] = ??? 11
  • 12. Predicate - can we map (define Functor)? case class Predicate[A](fun: A => Boolean) import cats.Functor val predicateFuncor: Functor[Predicate] = new Functor[Predicate] { def map[A, B](fa: Predicate[A])(f: A => B): Predicate[B] = ??? } 12
  • 13. Predicate - but we can prepend! case class Predicate[A](fun: A => Boolean) val hasEnoughLength: Predicate[Int] = Predicate(a => a > 3) def len(s: String): Int = s.length val isValidCode: Predicate[String] = Predicate[String](len andThen hasEnoughLength.fun) 13
  • 14. case class Predicate[A](fun: A => Boolean) def contramap[A, B](pred: Predicate[A])(fba: B => A): Predicate[B] = Predicate[B](fba andThen pred.fun) Predicate - generalize prepend 14
  • 15. Example2 - Show trait Show[F] { def show(f: F): String } Scalaz github.com/scalaz/scalaz/blob/series/7.3.x/core/src/main/scala/scalaz/Show.scala#L51-L53 15
  • 16. Example2 - Can we reuse existing Show? trait Show[A] { def show(a: A): String } case class Processor(name: String) case class Multicore(name: String, coreCount: Int) val sp: Show[Processor] = new Show[Processor] { override def show(a: Processor): String = s"Processor ${a.name}" } def asProcessor(mc: Multicore): Processor = Processor(s"${mc.coreCount} x ${mc.name}") 16
  • 17. Example2 - Can we define Functor for Show? trait Show[A] { def show(a: A): String } val showFunctor: Functor[Show] = new Functor[Show] { override def map[A, B](fa: Show[A])(f: A => B): Show[B] = ??? } 17
  • 18. Example2 - no! but we can prepend trait Show[A] { def show(a: A): String } def contramap[A, B](fa: Show[A])(f: B => A): Show[B] = new Show[B] { override def show(a: B): String = fa.show(f(a)) } 18
  • 19. Common pattern - prepend to input 1/3 trait Show[A] { def show(a: A): String } def prepend[A, B](fa: Show[A])(f: B => A): Show[B] = new Show[B] { override def show(a: B): String = fa.show(f(a)) } 19
  • 20. Common pattern - prepend to input 2/3 case class Predicate[A](fun: A => Boolean) def prepend[A, B](pred: Predicate[A])(fba: B => A): Predicate[B] = Predicate[B](fba andThen pred.fun) 20
  • 21. Common pattern - prepend to input Contravariant trait InputPrepender[F[_]] { def prepend[A, B] (fa: F[A])(f: B => A): F[B] } 21
  • 22. Mathematicians and names :) trait Contravariant[F[_]] { def contramap[A, B] (fa: F[A])(f: B => A): F[B] } 22
  • 23. Contravariant - like a Functor but flip! trait Functor[F[_]] { def map[A, B] (fa: F[A]) (f: A => B): F[B] } trait Contravariant[F[_]] { def contramap[A, B] (fa: F[A]) (f: B => A): F[B] } 23
  • 24. Contravariant Functor - input + ability to prepend Functor is “full of” A’s (container A, function producing A) F[A] we can map A => B and we get F[B] F[A] we can contramap B => A and we get F[B] Contravariant “needs” A (index of container, function consuming A) 24
  • 26. Exercises - Contravariant for scala.math.Equiv trait Equiv[T] { def equiv(x: T, y: T): Boolean } val EquivContra: Contravariant[Equiv] = new Contravariant[Equiv] { override def contramap[A, B](fa: Equiv[A])(f: B => A): Equiv[B] = ??? } Much more: https://github.com/lemastero/contravariant_profunctor_exercises/blob/master/src/main/scala/contra_pro/Exercise1_Contravariant. scala 26
  • 27. Contravariant - example Function1 def function1Contravariant[R]: Contravariant[? => R] = new Contravariant[? => R] { def contramap[A, B](r: A => R)(f: B => A) = r compose f } 27
  • 28. Contravariant - example Function1 def function1Contravariant[R]: Contravariant[? => R] = new Contravariant[? => R] { def contramap[A, B](r: A => R)(f: B => A) = r compose f } Glorified compose of Function1 !!! 28
  • 29. Contravariant - example Reader (1) case class Reader[C, V](run: C => V) 29
  • 30. Contravariant - example Reader - Functor case class Reader[C, V](run: C => V) def readerFunctor[C] = new Functor[Reader[C,?]] { def map[A, B](x: Reader[C, A])(f: A => B): Reader[C, B] = Reader(x.run andThen f) } 30
  • 31. Contravariant - example Reader - Monad case class Reader[C, V](run: C => V) def readerMonad[C] = new Monad[Reader[C, ?]] { def map[A, B](x: Reader[C, A])(f: A => B): Reader[C, B] = Reader(x.run andThen f) def pure[A](a: A): Reader[C, A] = new Reader(_ => a) def flatMap[A, B](ma: Reader[C, A])(f: A => Reader[C, B]) = ??? } 31
  • 32. Contravariant - example Reader - Contravariant case class Reader[C, V](run: C => V) def readerContra[V] = new Contravariant[Reader[?, V]] { def contramap[A, B](fa: Reader[A, V])(f: B => A): Reader[B, V] = Reader(f andThen fa.run) } 32
  • 33. Functor laws fmap id = id fmap f . fmap g = fmap (f . g) Contravariant laws contramap id = id contramap f . contramap g = contramap (g . f) Contravariant - laws in Haskell 33
  • 34. Contravariant - laws in Scala 34
  • 36. Contravariant - FunctionN parameters all but last trait Function2[-T1, -T2, +R]{ def apply(v1: T1, v2: T2): R } trait Function3[-T1, -T2, -T3, +R]{ def apply(v1: T1, v2: T2, v3: T3): R } //... All parameters are in negative position, co we could define Contravariant instance for it. (Or even BiContravariant, TriContravariant, ... if they existed :) 36
  • 37. Contravariant * Contravariant = Covariant Compose contravariant functors: https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/Contravariant.scala#L11-L15 Input of your input is not my input But it’s input is ... https://github.com/lemastero/scala_typeclassopedia/blob/master/src/main/scala/contravariant/HoFStructure.scala 37
  • 38. Contravariant Functors everywhere ● Kafka producer ● HTTP endpoints ● DB Repository ● S3 client ● ... 38
  • 39. Contravariant Functors everywhere but why? We don’t want to map … and change HttpApi[Json] into HttpApi[Ints] We might want to: ● provide part of configuration ● change config file path to parsed case class with configuration ● set execution context for all operations ● provide dependency like AvroKafkaDeserializer and schema registry config (clients don’t have to worry about it) ● add defaults and require only Option[Config] ● ... 39
  • 40. Contravariant - examples in open source libs Encoder in Scodec: github.com/scodec/scodec/blob/series/1.11.x/shared/src/main/scala/scodec/Encoder.scala#L40-L47 Schedule/ZSink/ZQueue in ZIO (contramap, provideSome): https://github.com/zio/zio/search?q=contramap&unscoped_q=contramap Logger https://github.com/zio/zio-logging/issues/7 JSON Encoder in Circe https://github.com/circe/circe/blob/master/modules/core/shared/src/main/scala/io/circe/Encoder.scala#L53-L55 40
  • 42. Contravariant - discrimination sort youtube.com/watch?v=cB8DapKQz-I Sorting in linear time Edward Kmett in Haskell In Scala? 42
  • 44. case class Serializer[A](run: A => Array[Byte]) val strSerial = Serializer[String](_.getBytes) val intSerial = Serializer[Int](_.toString.getBytes) GOTO Github: https://github.com/lemastero/contravariant_profunctor_exercises/blob/master/src/test/scala/contra_pro/DivideSpec.scala Divide (1) - Serialization 44
  • 45. val fragmentSerial = Serializer[Fragment] { frag => val a1 = strSerial.run(frag.name) val a2 = intSerial.run(frag.size) a1 ++ a2 } val serialized = fragmentSerial.run(Fragment("Area", 52)) new String(serialized ) mustBe "Area52" Divide (2) - How to combine serializers? 45
  • 46. trait Divide[F[_]] extends Contravariant[F] { def divide[A,B,C](f: A => (B,C), fb: F[B], fc: F[C]): F[A] } Divide (3) - abstraction 46
  • 47. val fragmentDivide: Divide[Serializer] = new Divide[Serializer] { def divide2[A1, A2, Z](s1: => Serializer[ A1], s2: => Serializer[ A2])(f: Z => (A1, A2)): Serializer[ Z] = Serializer{ frag => val (a1,a2) = f(frag) s1.run(a1) ++ s2.run(a2) } } Divide (4) 47
  • 48. val fragAsTuple: Fragment => (String, Int) = frag => (frag.name, frag.size) val fragSerial: Serializer[Fragment] = Divide[Serializer].divide(strSerial, intSerial)(fragAsTuple) Divide (5) 48
  • 49. val fragAsTuple: Fragment => (String, Int) = frag => (frag.name, frag.size) val fragSerial: Serializer[Fragment] = Divide[Serializer].divide(strSerial, intSerial)(fragAsTuple) val serialized = fragSerial.run(Fragment("Area", 52)) new String(serialized ) mustBe "Area52" Divide - Run 49
  • 51. Define full laws for Divide as in Haskell hackage.haskell.org/package/contravariant/docs/Data-Functor-Contravariant-Divisible.html#g:4 Not simplified as in Scalaz and Cats! Contravariant - Divide - Challenge 51
  • 53. Functor - Signature def map[A,B](fa: F[A])(f: A => B): F[B] Functor 53
  • 54. Apply - Signature def map[A,B](fa: F[A])(f: A => B): F[B] Functor def ap[A,B](ff: F[A => B])(fa: F[A]): F[B] Apply 54
  • 55. Applicative - Signature def map[A,B](fa: F[A])(f: A => B): F[B] Functor def ap[A,B](ff: F[A => B])(fa: F[A]): F[B] Apply def pure[A](value: A): F[A] Applicative 55
  • 56. Contravariant Functors - arrows reversed //def map (F[A], A => B): F[B] Functor def contramap (F[A], B => A): F[B] Contravariant (Contravariant Functor) //def map2 ((A,B) => Z, F[A], F[B]): F[Z] Apply (not ap!) def divide (Z => (A,B), F[A], F[B]): F[Z] Divide (Contravariant Apply) //def pure: ( () => A ) => F[A] Applicative def conquer: ( A => () ) => F[A] Divisible (Contravariant Applicative) 56
  • 57. Good general theory does not search for the maximum generality, but for the right generality. Saunders Mac Lane Choose the right level of abstraction, to see the problem more clearly Eugenia Cheng, Category in Life https://www.youtube.com/watch?v=ho7oagHeqNc Thank you :) 57