Skip to content

Instantly share code, notes, and snippets.

@luciferous
Last active August 29, 2015 13:56
Show Gist options
  • Save luciferous/9265677 to your computer and use it in GitHub Desktop.
Save luciferous/9265677 to your computer and use it in GitHub Desktop.
Generalized profunctor composition
trait Profunctor[F[_, _, _, _], P[_, _]] {
def lmap[A, B, C](f: F[C, A, B, B])(p: P[A, B]): P[C, B]
def rmap[A, B, C](g: F[A, A, B, C])(p: P[A, B]): P[A, C]
def dimap[A, B, C, D](h: F[C, A, B, D])(p: P[A, B]): P[C, D]
}
object Profunctor {
type FilterLike[A, B, C, D] = Filter[A, D, B, C]
private trait FilterPartial[A, B] { type Apply[C, D] = Filter[C, D, A, B] }
implicit def filterFilter[A, B] = new Profunctor[FilterLike, FilterPartial[A, B]#Apply] {
def lmap[C, D, E](f: Filter[E, D, C, D])(p: Filter[C, D, A, B]) = f andThen p
def rmap[C, D, E](g: Filter[C, E, C, D])(p: Filter[C, D, A, B]) = g andThen p
def dimap[C, D, E, F](h: Filter[E, F, C, D])(p: Filter[C, D, A, B]) = h andThen p
}
implicit object filterService extends Profunctor[FilterLike, Service] {
def lmap[C, D, E](f: Filter[E, D, C, D])(p: Service[C, D]) = f andThen p
def rmap[C, D, E](g: Filter[C, E, C, D])(p: Service[C, D]) = g andThen p
def dimap[C, D, E, F](h: Filter[E, F, C, D])(p: Service[C, D]) = h andThen p
}
implicit object filterServiceFactory extends Profunctor[FilterLike, ServiceFactory] {
def lmap[C, D, E](f: Filter[E, D, C, D])(p: ServiceFactory[C, D]) = f andThen p
def rmap[C, D, E](g: Filter[C, E, C, D])(p: ServiceFactory[C, D]) = g andThen p
def dimap[C, D, E, F](h: Filter[E, F, C, D])(p: ServiceFactory[C, D]) = h andThen p
}
sealed trait S[F[_,_,_,_], P[_,_], A, B]
case class Leaf[F[_,_,_,_], P[_,_], A, B]
(p: P[A, B])(implicit pro: Profunctor[F, P])
extends S[F, P, A, B]
case class Dimap[F[_,_,_,_], P[_,_], A, B, C, D]
(f: F[C, A, B, D], p: S[F, P, A, B])(implicit pro: Profunctor[F, P])
extends S[F, P, C, D]
def flatten[F[_,_,_,_], P[_,_], A, B]
(s: S[F, P, A, B])(implicit pro: Profunctor[F, P]): P[A, B] =
s match {
case Leaf(p) => p
case Dimap(f, p) => pro.dimap(f)(flatten(p))
}
def print[F[_,_,_,_], P[_,_], A, B]
(s: S[F, P, A, B])(implicit pro: Profunctor[F, P]): String =
s match {
case Leaf(p) => p.toString
case Dimap(f, p) => print(p) + "\n" + f.toString
}
}
object Main {
import Profunctor._
def f: FilterLike[Option[Int], Int, Boolean, String] =
Filter.mk[Option[Int], String, Int, Boolean] { (_, _) => Future.value("hi") }
def g: FilterLike[Int, Int, Boolean, Boolean] =
Filter.mk[Int, Boolean, Int, Boolean] { (_, _) => Future.True }
def h = Service.mk { _: Int => Future.False }
val x = Dimap(f, (Dimap(g, Leaf(h))))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment