Skip to content

Instantly share code, notes, and snippets.

@matsu-chara
Last active August 29, 2015 14:25
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 matsu-chara/7b33d8a58f064fd8cda7 to your computer and use it in GitHub Desktop.
Save matsu-chara/7b33d8a58f064fd8cda7 to your computer and use it in GitHub Desktop.
FreeMonoid
object FreeMonoidComponent {
import MonoidComponent._
// FreeMonoidの定義
type FreeMonoid[A] = List[A]
object FreeMonoid {
def apply[A](xs: A*): FreeMonoid[A] = xs.toList
val empty = Nil
}
// インスタンス定義
implicit def monoidFreeMonoidInstance[A] = new Monoid[FreeMonoid[A]] {
override def <>(l1: FreeMonoid[A], l2: FreeMonoid[A]): FreeMonoid[A] = l1 ++ l2
override val mempty = FreeMonoid.empty
}
// インタプリタの定義
def interpretMonoid[A, B: Monoid](f: (A => B), a: FreeMonoid[A]): B = (f, a) match {
case (f, FreeMonoid.empty) => implicitly[Monoid[B]].mempty
case (f, a :: as) => <>(f(a), interpretMonoid(f, as))
}
}
object FreeMonoidTest {
import FreeMonoidComponent._
sealed trait BankOp
case class Deposit(d: Int) extends BankOp
case class Withdraw(w: Int) extends BankOp
def interpretOp(b: BankOp): Int = b match {
case Deposit(d) => d
case Withdraw(w) => -w
}
def interpret(bs: FreeMonoid[BankOp]): Int = interpretMonoid(interpretOp, bs)
def main(args: Array[String]) = {
val program = FreeMonoid(Deposit(10), Withdraw(5), Withdraw(2), Deposit(3))
// FreeMagma[String]で、String => Intな関数fを適用しながらMagma[Int]を利用したのと同じ原理。
// BankOpはMonoidではないが(=Monoidのインスタンスを具体的に定義していないが)、
// FreeMonoid[BankOp]の中身を取り出しながら、BankOp => Intな関数fを適用していくと
// Monoid[Int]を利用することが出来る。
// BankOpでもMonoidっぽいことができるようになった!
val result = interpret(program)
println(result) // 6
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment