Skip to content

Instantly share code, notes, and snippets.

@gustavofranke
Created September 26, 2019 16:50
Show Gist options
  • Save gustavofranke/5a5b1214f63f17faa645a252b521573c to your computer and use it in GitHub Desktop.
Save gustavofranke/5a5b1214f63f17faa645a252b521573c to your computer and use it in GitHub Desktop.
/**
* @see https://www.youtube.com/watch?v=UjSQlUjuZWQ
* @see https://bartoszmilewski.com/2019/07/03/programming-with-universal-constructions/
*/
object BartozUniversalsConstructions {
// C
// / | \
// / | \
// / | \
// / | h \
// f / v \ g
// | AxB |
// | pi2 / \ pi1 |
// | / \ |
// | / \ |
// | / \ |
// v v v v
// A B
type A
type B
type C
val product: (A, B) = ???
val pi1 = (product: (A, B)) => product._1
val pi2 = (product: (A, B)) => product._2
val h: C => (A, B) = ???
// val f = pi1 compose h = ???
// val g = pi2 compose h = ???
def fanout[C, A, B](fst: C => A, snd: C => B): C => (A, B) = c => (fst(c), snd(c))
// Unit
// / | \
// / | \
// / | \
// / | h \
// f / v \ g
// | AxB |
// | pi2 / \ pi1 |
// | / \ |
// | / \ |
// | / \ |
// v v v v
// A B
val unit: Unit = ()
val x: Unit => A = ???
val y: Unit => B = ???
def fanin[C, A, B](h: C => (A, B)): (C => A, C => B) = (h(_)._1, h(_)._2)
// (A, B)
// / | \
// ._1/ | \ ._2
// / | \
// / |bimap \
// A v v v B
// | (A', B') |
// | ._1 / \ ._2 |
// | / \ |
// | / \ |
// | / \ |
// v v v v
// A' B'
def bimap[A, A1, B, B1](f: A => A1, g: B => B1): ((A, B)) => (A1, B1) =
fanout(f compose (_._1), g compose (_._2))
def either[C, A, B](f: A => C, g: B => C): Either[A, B] => C = _.fold(f, g)
// {
// case Left(a) => f(a)
// case Right(b) => g(b)
// }
// A B
// |\ right/ |
// | \left / |
// | \ / |
// | v v |
// f | A + B | g
// \ |either/
// \ | /
// \ | /
// \ | /
// v v v
// C
def foo[C, A, B](h: Either[A, B] => C): (A => C, B => C) = (a => h(Left(a)), b => h(Right(b)))
// AxC BxC
// |\ right/ |
// | \left / |
// | \ / |
// | v v |
// f | AxC + BxC | g
// \ | /
// \ |h /
// \ | /
// \ | /
// v v v
// (A + B) x C
def left[A](a: A): Either[A, Nothing] = Left(a)
def right[B](b: B): Either[Nothing, B] = Right(b)
def distRight[C, A, B]: Either[(A, C), (B, C)] => (Either[A, B], C) =
either(bimap(left(_), identity(_)), bimap(right(_), identity(_)))
def distLeft[C, A, B]: ((Either[A, B], C)) => Either[(A, C), (B, C)] =
uncurry(either(curry(left(_)), curry(right(_))))
def curry[C, A, B](f: ((C, A)) => B): C => A => B = c => Function.untupled(f)(c, _)
def uncurry[C, A, B](f: C => A => B): ((C, A)) => B = Function.tupled(f(_)(_))
// def choice[A, A1, B, B1](f: A => A1, g: B => B1): Either[A, B] => Either[A1, B1] = ???
}
@erinmez
Copy link

erinmez commented Sep 27, 2019

Hi there,
Thanks a lot for this nice summarization! While quickly glancing over the first two diagrams, I think that the names of the arrows p1 & p2 need to be switched.
Cheers, Tanju

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment