Last active
August 29, 2015 14:14
-
-
Save awekuit/5f1d26656e2fcc6376b2 to your computer and use it in GitHub Desktop.
(Coyoneda編) 型引数の基本から学ぶ、FreeモナドとCoyoneda http://awekuit.hatenablog.com/entry/2015/01/30/172010
This file contains 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 scala.language.higherKinds | |
import scala.language.implicitConversions | |
import scala.language.reflectiveCalls | |
trait Functor[F[_]] { | |
def map[A, B](m: F[A])(f: A => B): F[B] | |
} | |
implicit def functorOps[F[_] : Functor, A](self: F[A]) = new { | |
def map[B](f: A => B): F[B] = implicitly[Functor[F]].map(self)(f) | |
} | |
abstract class LazyMap[F[_], A] { coyo => | |
type I | |
val fi: F[I] | |
val k: I => A | |
import LazyMap.apply | |
def map[B](f: A => B): LazyMap[F, B] = apply[F,I,B](fi)(f compose k) | |
def run(implicit F: Functor[F]): F[A] = F.map(fi)(k) | |
} | |
object LazyMap { | |
def apply[F[_], A, B](fa: F[A])(_k: A => B): LazyMap[F, B] = | |
new LazyMap[F, B]{ | |
type I = A | |
val k = _k | |
val fi = fa | |
} | |
def liftLazyMap[F[_], A](x: F[A]) = apply[F,A,A](x)(identity[A]) | |
implicit def lazymapFunctor[F[_]] : Functor[({type LM[X] = LazyMap[F, X]})#LM] = { | |
type LM[X] = LazyMap[F, X] | |
new Functor[LM] { | |
def map[A, B](fa: LazyMap[F, A])(f: A => B): LazyMap[F, B] = fa.map(f) | |
} | |
} | |
} | |
abstract class HKFold[F[_] : Functor, A] { | |
def point[B] (x: B): HKFold[F, B] = | |
F0[F,B](x) | |
def map[B] (f: A => B): HKFold[F, B] = | |
flatMap(x => point(f(x))) | |
def flatMap[B](f: A => HKFold[F, B]): HKFold[F, B] | |
} | |
case class F0[F[_] : Functor, A](x: A) extends HKFold[F, A] { | |
def flatMap[B](f: A => HKFold[F, B]): HKFold[F, B] = | |
f(x) | |
} | |
case class F1[F[_] : Functor, A](x: F[A]) extends HKFold[F, A] { | |
def flatMap[B](f: A => HKFold[F, B]): HKFold[F, B] = { | |
val y = x.map(f) | |
F3[F,B](y) | |
} | |
} | |
case class F3[F[_] : Functor, A](x: F[HKFold[F, A]]) extends HKFold[F, A] { | |
def flatMap[B](f: A => HKFold[F, B]): HKFold[F, B] = { | |
val res = x.map{y => | |
y.flatMap(z => f(z)) | |
} | |
F3(res) | |
} | |
} | |
import LazyMap._ | |
case class MyBox[A](x: A) | |
// 型推論を補うため. | |
type LMMyBox[X] = LazyMap[MyBox, X] | |
// 型の記述を省力化するための関数(LMMyBox[A]として返す) | |
def lazyMyBox[A](x: MyBox[A]): LMMyBox[A] = liftLazyMap(x) | |
val res = for { | |
a <- F1(lazyMyBox(MyBox(3))) | |
b <- F1(lazyMyBox(MyBox("5"))) | |
c <- F1(liftLazyMap(MyBox(10)) : LMMyBox[Int]) // もしlazyMyBox関数を使わないならこのように型注釈が必要 | |
} yield (a * b.toInt + c).toString + "です!" | |
implicit val myboxFunctor = new Functor[MyBox] { | |
def map[A,B](fa: MyBox[A])(f: A => B): MyBox[B] = MyBox(f(fa.x)) | |
} | |
def interpreter[A](program: HKFold[LMMyBox, A]): A = program match { | |
case F0(a) => a | |
case F3(a) => a.run match { | |
case MyBox(b) => interpreter(b) | |
} | |
} | |
interpreter(res) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment