Skip to content

Instantly share code, notes, and snippets.

@yasuabe
Created February 24, 2018 18:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yasuabe/a4634be0d1ecfdf63e5558097eca4657 to your computer and use it in GitHub Desktop.
Save yasuabe/a4634be0d1ecfdf63e5558097eca4657 to your computer and use it in GitHub Desktop.
import cats.data.{Kleisli, Nested, Tuple2K}
import cats.implicits._
import cats.{Distributive, Functor, Id, Traverse, ~>}
// def distribute[G[_]: Functor, A, B](ga: G[A])(f: A => F[B]): F[G[B]]
// def cosequence[G[_]: Functor, A](ga: G[F[A]]): F[G[A]] = distribute(ga)(identity)
// Function0 ------------------------------
// F = () => ?
val d0 = Distributive[() => ?]
// G = List, A = Char, B = String
// G[A] = List[Char], F[B] = () => String, F[G[B]] = () => List[String]
val afb0: Char => () => String = c => () => s"<$c>"
val ga0 = List('a', 'b')
d0.distribute(ga0)(afb0).apply // List(<a>, <b>)
ga0.distribute(afb0).apply // List(<a>, <b>)
// G = List, A = Char
// G[F[A]] = List[() => Char], F[G[A]] = () => List[Char]
val gfa0 = List.fill(3)(() => '7')å
d0.cosequence(gfa0).apply // List(7, 7, 7)
gfa0.cosequence[() => ?, Char].apply // List(7, 7, 7)
// Function1 ------------------------------
// F = Int => ?
val d1 = Distributive[Int => ?]
// G = Option, A = Char, B = String
// G[A] = Option[Char], F[B] = Int => String, F[G[B]] = Int => Option[String]
val afb1: Char => Int => String = c => n => c.toString * n
val ga1 = Option('a')
d1.distribute(ga1)(afb1).apply(3) // Some(aaa)
ga1.distribute(afb1).apply(3) // Some(aaa)
// G = Option, A = String
// G[F[A]] = List[() => Char], F[G[A]] = () => List[Char]
val gfa1: Option[Int => String] = Option(n => "a" * n)
d1.cosequence[Option, String](gfa1).apply(3) // Some(aaa)
d1.cosequence[Option, String](None).apply(3) // None
gfa1.cosequence[Int => ?, String].apply(4) // Some(aaaa)
// Nested ------------------------------
// F = Nested[() => ?, Int => ?, A]
type FN[A] = Nested[() => ?, Int => ?, A]
val dn = Distributive[FN]
// G = Option, A = Char, B = String
// G[A] = Option[Char], F[B] = Int => String, F[G[B]] = Int => Option[String]
val afbn: Char => FN[String] = c => Nested(() => c.toString * _)
val gan = Option('a')
dn.distribute(gan)(afbn).value()(5) // Some(aaaaa)
gan.distribute(afbn).value()(3) // Some(aaa)
dn.distribute(gan)(afbn)
.map(_.map(s => s"<$s>")) // <-- (a)
.value()(3) // Some(<aaa>)
// G = List, A = String
// G[F[A]] = List[FN[String]], F[G[A]] = FN[List[String]]
val gfan: List[FN[String]] = List(Nested(() => "n" * _), Nested(() => "m" * _))
val nested = dn.cosequence[List, String](gfan)
nested.value()(3) // List(nnn, mmm)
nested.map(os => s"<$os>").value()(2) // <List(nn, mm)>
gfan.cosequence[FN, String].value()(2) // List(nn, mm)
val func0ToId: Function0 ~> Id = new (Function0 ~> Id) {
override def apply[A](fa: () => A) = fa()
}
gan.distribute(afbn).mapK(func0ToId).value(3) // Some(aaa)
// Kleisli ------------------------------
// F = Kleisli[() => ?, Int, A]
type FK[A] = Kleisli[() => ?, Int, A]
val dk = Distributive[FK]
// G = Option, A = Char, B = String
// G[A] = Option[Char], F[B] = Int => String, F[G[B]] = Int => Option[String]
val afbk: Char => FK[String] = c => Kleisli(n => () => c.toString * n)
val gak = Option('a')
dk.distribute(gak)(afbk).run(7)() // Some(aaaaaaa)
gak.distribute(afbk).run(7)() // Some(aaaaaaa)
// G = Option, A = String
// G[F[A]] = Option[FK[String]], F[G[A]] = FK[Option[String]]
val gfak: Option[FK[String]] = Option(Kleisli(n => () => "k" * n))
dk.cosequence[Option, String](gfak).run(8)() // Some(kkkkkkkk)
dk.cosequence[Option, String](None).run(8)() // None
gfak.cosequence[FK, String].run(6)() // Some(kkkkkk)
// Tuple2K --------------------------
// F = Tuple2K[Int => ?, Boolean => ?, A]
type FT[A] = Tuple2K[Int => ?, Boolean => ?, A]
val dt = Distributive[FT]
// G = Option, A = Char, B = String
// G[A] = Option[Char], F[B] = Int => String, F[G[B]] = Int => Option[String]
val afbt: Char => FT[String] = c => Tuple2K(c.toString * _, b => s"<$c, $b>")
val gat = Option('a')
dt.distribute(gat)(afbt).first(2) // Some(aa)
gat.distribute(afbt).second(true) // Some(<a, true>)
// G = Option, A = String
// G[F[A]] = Option[FK[String]], F[G[A]] = FK[Option[String]]
val gfat: Option[FT[String]] = Option(Tuple2K(n => s"<n>", b => s"<$b>"))
dt.cosequence[Option, String](None).first(2) // None
gfat.cosequence[FT, String].second(false) // Some(<false>)
// compose --------------------------
type TC[A] = Int => Double => A
val composed: Distributive[TC] = Distributive[Int => ?].compose[Double => ?]
def f(o: Option[TC[String]]) = composed.cosequence[Option, String](o).apply(3)(0.14)
f(Option(n => d => s"π ≒ ${n + d}")) // Some(π ≒ 3.14)
f(None) // None
// traverse ----------------------------------
val h: Double => Int => String = d => n => s"${n+d}"
val o = Option(0.14)
val s1 = Distributive[Int => ?].distribute[Option, Double, String](o)(h)
val t1 = Traverse [Option] .traverse [Int => ?, Double, String](o)(h)
assert(s1(3) == t1(3)) // 共に Some(3.14)
val of: Option[Int => String] = Option(n => s"n = $n")
val s2 = Distributive[Int => ?].cosequence[Option, String](of)
val t2 = Traverse [Option] .sequence [Int => ?, String](of)
assert(s2(100) == t2(100)) // 共に Some(n = 100)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment