/core/src/main/scala/scalaz/Cokleisli.scala

http://github.com/scalaz/scalaz · Scala · 124 lines · 94 code · 30 blank · 0 comment · 0 complexity · 5c883cdf686df785bfa3932b3c1a6134 MD5 · raw file

  1. package scalaz
  2. final case class Cokleisli[F[_], A, B](run: F[A] => B) { self =>
  3. def apply(fa: F[A]): B =
  4. run(fa)
  5. def dimap[C, D](f: C => A, g: B => D)(implicit b: Functor[F]): Cokleisli[F, C, D] =
  6. Cokleisli(c => g(run(b.map(c)(f)))) // b.map(run(f(c)))(g))
  7. def contramapValue[C](f: F[C] => F[A]): Cokleisli[F, C, B] = Cokleisli(run compose f)
  8. def map[C](f: B => C): Cokleisli[F, A, C] = Cokleisli(f compose run)
  9. def flatMap[C](f: B => Cokleisli[F, A, C]): Cokleisli[F, A, C] =
  10. Cokleisli(fa => f(self.run(fa)).run(fa))
  11. def <<=(a: F[A])(implicit F: Cobind[F]): F[B] =
  12. F.extend(a)(run)
  13. def =>=[C](c: Cokleisli[F, B, C])(implicit F: Cobind[F]): Cokleisli[F, A, C] =
  14. Cokleisli(fa => c run (<<=(fa)))
  15. def compose[C](c: Cokleisli[F, C, A])(implicit F: Cobind[F]): Cokleisli[F, C, B] =
  16. c =>= this
  17. def =<=[C](c: Cokleisli[F, C, A])(implicit F: Cobind[F]): Cokleisli[F, C, B] =
  18. compose(c)
  19. def endo(implicit ev: B === A): Endomorphic[Cokleisli[F, *, *], A] =
  20. Endomorphic[Cokleisli[F, *, *], A](ev.subst[Cokleisli[F, A, *]](this))
  21. }
  22. object Cokleisli extends CokleisliInstances {
  23. }
  24. sealed abstract class CokleisliInstances0 {
  25. implicit def cokleisliCompose[F[_]](implicit F0: Cobind[F]): Compose[Cokleisli[F, *, *]] =
  26. new CokleisliCompose[F] {
  27. override implicit def F = F0
  28. }
  29. implicit def cokleisliProfunctor[F[_]: Functor]: Profunctor[Cokleisli[F, *, *]] =
  30. new CokleisliProfunctor[F] {
  31. def F = implicitly
  32. }
  33. }
  34. sealed abstract class CokleisliInstances extends CokleisliInstances0 {
  35. implicit def cokleisliMonad[F[_], R]: Monad[Cokleisli[F, R, *]] with BindRec[Cokleisli[F, R, *]] =
  36. new CokleisliMonad[F, R] {}
  37. implicit def cokleisliArrow[F[_]](implicit F0: Comonad[F]): Arrow[Cokleisli[F, *, *]] with ProChoice[Cokleisli[F, *, *]] =
  38. new CokleisliArrow[F] {
  39. override implicit def F = F0
  40. }
  41. }
  42. private trait CokleisliMonad[F[_], R] extends Monad[Cokleisli[F, R, *]] with BindRec[Cokleisli[F, R, *]] {
  43. override def map[A, B](fa: Cokleisli[F, R, A])(f: A => B) = fa map f
  44. override def ap[A, B](fa: => Cokleisli[F, R, A])(f: => Cokleisli[F, R, A => B]) = f flatMap (fa map _)
  45. def point[A](a: => A) = Cokleisli(_ => a)
  46. def bind[A, B](fa: Cokleisli[F, R, A])(f: A => Cokleisli[F, R, B]) = fa flatMap f
  47. def tailrecM[A, B](a: A)(f: A => Cokleisli[F, R, A \/ B]): Cokleisli[F, R, B] = {
  48. @annotation.tailrec
  49. def go(a0: A)(r: F[R]): B =
  50. f(a0).run(r) match {
  51. case -\/(a1) => go(a1)(r)
  52. case \/-(b) => b
  53. }
  54. Cokleisli(go(a))
  55. }
  56. }
  57. private trait CokleisliCompose[F[_]] extends Compose[Cokleisli[F, *, *]] {
  58. implicit def F: Cobind[F]
  59. override def compose[A, B, C](f: Cokleisli[F, B, C], g: Cokleisli[F, A, B]) = f compose g
  60. }
  61. private trait CokleisliProfunctor[F[_]] extends Profunctor[Cokleisli[F, *, *]] {
  62. implicit def F: Functor[F]
  63. override def dimap[A, B, C, D](fab: Cokleisli[F, A, B])(f: C => A)(g: B => D) =
  64. fab.dimap(f, g)
  65. override final def mapfst[A, B, C](fa: Cokleisli[F, A, B])(f: C => A) =
  66. Cokleisli[F, C, B](fc => fa(F.map(fc)(f)))
  67. override final def mapsnd[A, B, C](fa: Cokleisli[F, A, B])(f: B => C) =
  68. fa map f
  69. }
  70. private trait CokleisliArrow[F[_]]
  71. extends Arrow[Cokleisli[F, *, *]]
  72. with ProChoice[Cokleisli[F, *, *]]
  73. with CokleisliProfunctor[F]
  74. with CokleisliCompose[F] {
  75. implicit def F: Comonad[F]
  76. def left[A, B, C](fa: Cokleisli[F, A, B]): Cokleisli[F, A \/ C, B \/ C] =
  77. Cokleisli { (ac: F[A \/ C]) =>
  78. F.copoint(ac) match {
  79. case -\/(a) => -\/(fa run (F.map(ac)(_ => a)))
  80. case \/-(b) => \/-(b)
  81. }
  82. }
  83. def right[A, B, C](fa: Cokleisli[F, A, B]): Cokleisli[F, C \/ A, C \/ B] =
  84. Cokleisli { (ac: F[C \/ A]) =>
  85. F.copoint(ac) match {
  86. case -\/(b) => -\/(b)
  87. case \/-(a) => \/-(fa run (F.map(ac)(_ => a)))
  88. }
  89. }
  90. def arr[A, B](f: A => B) = Cokleisli(a => f(F.copoint(a)))
  91. def id[A] = Cokleisli[F, A, A](F.copoint)
  92. def first[A, B, C](f: Cokleisli[F, A, B]) =
  93. Cokleisli[F, (A, C), (B, C)](w => (f.run(F.map(w)(ac => ac._1)), F.copoint(w)._2))
  94. }