Created
March 10, 2015 02:10
-
-
Save pjrt/2faa03eb35cf07dc69de to your computer and use it in GitHub Desktop.
Scala's version of this gist: https://gist.github.com/pjrt/8bc6b1bf413dafc92a9c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import language.higherKinds | |
// Scala doesn't have Identity, so here.... | |
object Id { | |
type Identity[+A] = A | |
implicit val identityFunctor: Functor[Identity] = new Functor[Identity] { | |
def fmap[A, B](f: A => B)(fa: Identity[A]) = f(fa) | |
} | |
} | |
import Id._ | |
// Scala doesn't have Functors, so here.... | |
trait Functor[F[_]] { | |
def fmap[A, B](f: A => B)(m: F[A]): F[B] | |
} | |
object Functor { | |
def apply[A[_]](implicit ev: Functor[A]) = ev | |
} | |
// Coyoneda definition | |
sealed trait Coyoneda[F[_], A] { | |
def map[B](f: A => B): Coyoneda[F, B] = this match { | |
case Coyo(g, v) => Coyo(f compose g, v) | |
} | |
} | |
case class Coyo[F[_], A, B](run: B => A, f: F[B]) extends Coyoneda[F, A] | |
object Coyoneda { | |
def liftCoyoneda[F[_], A](f : F[A]): Coyoneda[F, A] = | |
Coyo((a: A) => a, f) | |
def lowerCoyoneta[F[_]: Functor, A](coyo: Coyoneda[F, A]): F[A] = coyo match { | |
case Coyo(f, m) => Functor[F].fmap(f)(m) | |
} | |
// Eraser[A] is just a Coyoneda on identity | |
type Eraser[A] = Coyoneda[Identity, A] | |
def runEraser[A](eraser: Eraser[A]): A = lowerCoyoneta(eraser) | |
} | |
// Our typeclass | |
trait Foo[A] { | |
def foo(a: A): String | |
} | |
object Foo { | |
def apply[A](implicit ev: Foo[A]) = ev | |
def fooCoyo[A: Foo](f: A): Coyoneda.Eraser[String] = | |
Coyo[Identity, String, A](Foo[A].foo(_: A), f) | |
} | |
// Our types | |
case class Bar(run: Int) | |
object Bar { | |
implicit val foo: Foo[Bar] = new Foo[Bar] { | |
def foo(a: Bar) = a.run.toString | |
} | |
} | |
case class Baz(run: String) | |
object Baz { | |
implicit val foo: Foo[Baz] = new Foo[Baz] { | |
def foo(a: Baz) = a.run | |
} | |
} | |
object Main { | |
import Coyoneda._ | |
import Foo.fooCoyo | |
def main = { | |
val list: List[Eraser[String]] = | |
fooCoyo(Bar(1)) :: fooCoyo(Baz("Hello")) :: Nil | |
list.map(runEraser) // Prints List(1, Hello) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment