Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Extensible Effects with Scala/eff-with-scala

fuzyco
April 13, 2018

Extensible Effects with Scala/eff-with-scala

Extensible Effectsの概要とScalaでの実装の説明です

fuzyco

April 13, 2018
Tweet

More Decks by fuzyco

Other Decks in Technology

Transcript

  1. &YUFOTJCMF&⒎FDUT
    XJUI4DBMB

    View Slide

  2. Ϟνϕʔγϣϯ
    ݩͷࢿྉ͸ͪ͜ΒͰ͢
    IUUQTXXXTMJEFTIBSFOFU4BOTIJSP:PTIJEB
    FYUFOTJCMFF⒎FDUTJOEPUUZ
    4DBMB.BUTVSJʹ͓͍ͯIBMDBUYB͞Μͷ
    ʮ&YUFOTJCMF&⒎FDUTJO%PUUZʯ
    ͷ಺༰͕೉ͯ͘͠Θ͔Βͳ͔ͬͨͷͰɺ
    ࣗ෼ͳΓʹղऍͯ͠·ͱΊͯΈ·ͨ͠ɻ

    View Slide

  3. ΞδΣϯμ
    ɾ%PUUZͱ͸
    ɾ&YUFOTJCMF&⒎FDUTͱ͸
    ɾϞφυม׵ࢠ
    ɾϞφυελοΫ
    ɾ&YUFOTJCMF&⒎FDUTJO4DBMB
    4DBMB.BUTVSJͷεϥΠυͱղઆ৫Γަͥͯ࿩͍͖ͯ͠·͢

    View Slide

  4. ಘΒΕΔ஌ࣝ
    ɾϞφυม׵ࢠ
    ɾϞφυελοΫ
    ɾ'SFFϞφυ
    ɾ&YUFOTJCMF&⒎FDUT
    EPUUZ͸ϝΠϯ͡Ό͋Γ·ͤΜ

    View Slide

  5. ΞδΣϯμ
    ɾ%PUUZͱ͸
    ɾ&YUFOTJCMF&⒎FDUTͱ͸
    ɾϞφυม׵ࢠ
    ɾϞφυελοΫ
    ɾ&YUFOTJCMF&⒎FDUTJO%PUUZ

    View Slide

  6. %PUUZͱ͸
    w ࣍ੈ୅ͷ4DBMBίϯύΠϥ
    w 4DBMB͔Βඪ४ʹͳΔΒ͍͠
    w ݱࡏͷ࠷৽ͷόʔδϣϯ͸

    View Slide

  7. %PUUZͷಛ௃
    ɾ&OVNT
    ɾ5ZQF-BNCEBT
    ɾ*OUFSTFDUJPO5ZQFT
    ɾ6OJPO5ZQFT
    ɾ*NQMJDJU'VODUJPO5ZQFT
    ɾFUD

    View Slide

  8. 5ZQF-BNCEBT
    UZQF1BJS " "

    UZQF1BJS " "

    WBMQ1BJS

    %PUUZ
    4DBMB
    IUUQTXXXTMJEFTIBSFOFU4BOTIJSP:PTIJEBFYUFOTJCMFF⒎FDUTJOEPUUZ>

    View Slide

  9. 5ZQF-BNCEBT
    type FreeMonad[F[_]] =
    Monad[({ type λ[A] = Free[F, A] })#λ]
    type FreeMonad[F[_]] = Monad[[A] => Free[F, A]]
    %PUUZ
    4DBMB
    ܕͷ෦෼ద༻͕௚઀ॻ͚Δ
    IUUQTXXXTMJEFTIBSFOFU4BOTIJSP:PTIJEBFYUFOTJCMFF⒎FDUTJOEPUUZ>

    View Slide

  10. 6OJPO5ZQF
    val x: String | Int =
    if util.Random.nextBoolean() then "hoge" else 0
    IUUQTXXXTMJEFTIBSFOFU4BOTIJSP:PTIJEBFYUFOTJCMFF⒎FDUTJOEPUUZ>

    View Slide

  11. ΞδΣϯμ
    ɾ%PUUZͱ͸
    ɾ&YUFOTJCMF&⒎FDUTͱ͸
    ɾϞφυม׵ࢠ
    ɾϞφυελοΫ
    ɾ&YUFOTJCMF&⒎FDUTJO%PUUZ

    View Slide

  12. &YUFOTJCMF&⒎FDUT F⒎
    ͱ͸
    ϞφυελοΫΛ࣮ݱͨ͠΋ͷ
    Ϟφυม׵ࢠ
    ϞφυελοΫ
    ϞφυͷੵΈॏͶ

    Ϟφυͷแؚ
    4UBUF5 0QUJPO
    0QUJPO
    4UBUF5
    4UBUF
    4UBUF
    0QUJPO
    0QUJPO

    View Slide

  13. Ϟφυม׵ࢠ
    case class User(id: Long, firstName: Option[String], lastName: Option[String])
    def getUser(id: Long): Either[String, User] = ???
    def getUserName(id: Long): Either[String, Option[String]] = for {
    user } yield for {
    first last } yield s"$first $last"
    import cats.data.OptionT
    import cats.implicits._
    type StringEither = [A] => Either[String, A]
    def getUserName(id: Long): Either[String, Option[String]] = (for {
    user first last } yield s"$first $last").value
    GPS͕ࣜ࿈࠯ͯ͠ॻ͖ͮΒͯ͘ಡΈͮΒ͍
    ෳ਺ͷϞφυ͕ࠞࡏ͢Δ৔߹
    GPSࣜҰͭͰॻ͚Δ

    View Slide

  14. Ϟφυม׵ࢠͷ໰୊఺
    ߹੒͢ΔϞφυ͕૿͑Δͨͼʹɺܭࢉͷޮ཰͕མͪΔ
    ԼҐͷϞφυͷॲཧΛߦ͏ͷʹɺҰʑMJGUΛߦ͏ඞཁ͕͋Δ
    Ϟφυͷ߹੒ॱ͸ݻఆ͞Ε͍ͯͯɺ్தͰೖΕସ͑Δ͜ͱ͕Ͱ͖ͳ͍
    ϞφυΛ߹੒͢Δॱ൪ʹΑͬͯɺܭࢉͷҙຯ͕มΘΔ
    4UBUF5 0QUJPO
    0QUJPO
    4UBUF5

    View Slide

  15. Ϟφυม׵ࢠͷ໰୊఺
    ߹੒͢ΔϞφυ͕૿͑Δͨͼʹɺܭࢉͷޮ཰͕མͪΔ
    package cats
    package data
    final case class OptionT[F[_], A](value: F[Option[A]]) {
    def flatMap[B](f: A => OptionT[F, B])(implicit F: Monad[F]): OptionT[F, B] =
    flatMapF(a => f(a).value)
    def flatMapF[B](f: A => F[Option[B]])(implicit F: Monad[F]): OptionT[F, B] =
    OptionT(F.flatMap(value)(_.fold(F.pure[Option[B]](None))(f)))
    }
    ճϧʔϓ͕૸Δ

    View Slide

  16. Ϟφυม׵ࢠͷ໰୊఺
    ԼҐͷϞφυͷॲཧΛߦ͏ͷʹɺҰʑMJGUΛߦ͏ඞཁ͕͋Δ
    import cats.data.{ OptionT, StateT }
    import cats.instances.list._
    import cats.instances.either._
    type StringEither = [A] => Either[String, A]
    type OptionTEither = [A] => OptionT[StringEither, A]
    type StateTOptionTEither[S, C, A] = StateT[[C] => OptionTEither[C], S, A]
    def getUser(id: Long): Either[String, User] = ???
    def getState(id: Long): StateTOptionTEither[Int, User, Long] =
    StateT.liftF {
    OptionT.liftF {
    getUser(id)
    }.map { user =>
    user.id
    }
    }
    ԼҐͷ&JUIFSͷॲཧΛߦ͏ͨΊʹɺ
    ೋճMJGUΛݺΜͰ͍Δ

    View Slide

  17. Ϟφυม׵ࢠͷ໰୊఺
    Ϟφυͷ߹੒ॱ͸ݻఆ͞Ε͍ͯͯɺ్தͰೖΕସ͑Δ͜ͱ͕Ͱ͖ͳ͍
    ϞφυΛ߹੒͢Δॱ൪ʹΑͬͯɺܭࢉͷҙຯ͕มΘΔ
    import cats.data.{OptionT, State, StateT}
    import cats.instances.either._
    import cats.instances.option._
    // StateT[Option, Int, Int]
    StateT.modify[Option, Int] { _+1 }.flatMap { _ =>
    StateT.liftF[Option, Int, Int](None)
    }.run(10)
    // None
    type IntState = [A] => State[Int, A]
    // OptionT[IntState, Unit]
    OptionT.liftF[IntState, Unit] { State.modify{ _+1 } }.flatMap { _ =>
    OptionT.none[IntState, Unit]
    }.value.run(10).value
    // (11, None)
    ԼҐͷϞφυ͕0QUJPOͳͷͰɺ
    ్தͰࣦഊ͢Δͱ/POFʹͳΔ
    ԼҐͷϞφυ͕4UBUFͳͷͰɺ
    ్தͰࣦഊͯ͠΋಺෦ঢ়ଶ͸อ࣋͞ΕΔ

    View Slide

  18. ϞφυελοΫ
    Ϟφυม׵ࢠͷ໰୊Λղܾ͢Δख๏
    ߹੒͢ΔϞφυ͕૿͑Δͨͼʹɺܭࢉͷޮ཰͕མͪΔ
    ԼҐͷϞφυͷॲཧΛߦ͏ͷʹɺҰʑMJGUΛߦ͏ඞཁ͕͋Δ
    Ϟφυͷ߹੒ॱ͸ݻఆ͞Ε͍ͯͯɺ్தͰೖΕସ͑Δ͜ͱ͕Ͱ͖ͳ͍
    શͯͷܭࢉΛҰͭͷϞφυͷதͰߦ͏
    ϞφυΛ߹੒͢Δॱ൪ʹΑͬͯɺܭࢉͷҙຯ͕มΘΔ
    4UBUF
    4UBUF
    0QUJPO
    0QUJPO

    View Slide

  19. &YUFOTJCMF&⒎FDUT
    DBUDI SVO3FBEFS
    ɾϞφυͷॲཧΛΫϥΠΞϯτͱϋϯυϥͷ૬ޓ࡞༻Ͱଊ͑Δ
    ɾϞφυม׵ࢠͷϞφυελοΫΛɺҕৡؔ܎ͷνΣʔϯͱͯ͠ଊ͑Δ
    SVO&SSPS SVO4UBUF
    ҕৡ ҕৡ ҕৡ
    MJGU͕ෆཁɺ֊૚͕ͳ͍
    ϋϯυϥ
    ΫϥΠΞϯτϓϩάϥϜ
    ϦΫΤετ HFU UFMM UISPX

    View Slide

  20. &YUFOTJCMF&⒎FDUT
    &YUFOTJCMF&⒎FDUT
    cc
    'SFF.POBE

    0QFO6OJPO

    View Slide

  21. ͔͜͜Β͕ຊ୊
    ݩࢿྉͷҎ߱

    ͔͜͜Βઌͷαϯϓϧίʔυ͸ɺ
    EPUUZͷߏจͰॻ͔ͳͯ͘΋͍͚Δ෦෼͸
    4DBMBͰॻ͔Ε͍ͯ·͢

    View Slide

  22. ΞδΣϯμ
    ɾ%PUUZͱ͸
    ɾ&YUFOTJCMF&⒎FDUTͱ͸
    ɾϞφυม׵ࢠ
    ɾϞφυελοΫ
    ɾ&YUFOTJCMF&⒎FDUTJO4DBMB
    4DBMB.BUTVSJͷεϥΠυͱղઆ৫Γަͥͯ࿩͍͖ͯ͠·͢

    View Slide

  23. ࿩͢͜ͱ
    w 'SFF
    w 'SFFS
    w $PZPOFEB
    w 5ZQFBMJHOFE2VFVF
    w 'BTU'SFFS
    w &YUFOTJCMF&⒎FDUT
    w 0QFO6OJPO

    View Slide

  24. 'SFF.POBE
    case class Pure[F[_], A](a: A) extends Free[F, A]
    case class Impure[F[_], A](ff: F[Free[F, A]]) extends Free[F, A]
    sealed trait Free[F[_], A] {
    def map[B](f: A => B)(implicit F: Functor[F]): Free[F, B] = flatMap(a => Pure(f(a)))
    def flatMap[B](f: A => Free[F, B])(implicit F: Functor[F]): Free[F, B] =
    this match {
    case Pure(a) => f(a)
    case Impure(ff) => {
    Impure(F.map(ff)(_.flatMap(f)))
    }
    }
    }
    def lift[F[_], A](fa: F[A])(implicit F: Functor[F]): Free[F, A] =
    Impure(F.map(fa)(a => Pure(a)))
    'VODUPSΛϞφυʹม׵͢Δ
    ७ਮͳܭࢉ ෭࡞༻෇͖ͷܭࢉ

    View Slide

  25. 'SFF8SJUFS
    type Writer[W, A] = Free[[T] = Tell[W, T], A]
    // w: ग़ྗ஋ a: ܭࢉ͞Εͨ஋
    case class Tell[W, A](w: W, a: A) {
    def map[B](f: A => B) = Tell(w, f(a))
    }
    def tell[W](w: W): Writer[W, Unit] =
    Free.lift[[T] = Tell[W, T], Unit](Tell(w, ()))
    ܭࢉ͞Εͨ஋ͱ͸ผʹσʔλͷετϦʔϜΛੜ੒͢ΔϞφυ

    View Slide

  26. 'SFF8SJUFS
    type Writer[W, A] = Free[[T] = Tell[W, T], A]
    // w: ग़ྗ஋ a: ܭࢉ͞Εͨ஋
    case class Tell[W, A](w: W, a: A) {
    def map[B](f: A => B) = Tell(w, f(a))
    }
    def tell[W](w: W): Writer[W, Unit] =
    Free.lift[[T] = Tell[W, T], Unit](Tell(w, ()))
    def runAsList[W, A](free: Writer[W, A]): (List[W], A) =
    free match {
    case pure: Free.Pure[[T] = Tell[W, T], A] => (Nil, pure.a)
    case impure: Free.Impure[[T] = Tell[W, T], A] =>
    runAsList(impure.ff.a) match {
    case (ws, a) => (impure.ff.w :: ws, a)
    }
    }
    val e = for {
    _ _ } yield ()
    runAsList(e)
    // (List(hoge, fuga),())
    8SJUFS͕'VODUPSͰ͋Ε͹ɺ
    ϞφυʹͳΔ
    ܭࢉ͞Εͨ஋ʹͱ͸ผʹσʔλͷετϦʔϜΛੜ੒͢ΔϞφυ

    View Slide

  27. 'SFF8SJUFS
    implicit def tellFunctor[W] = new Functor[[A] = Tell[W, A]] {
    def map[A, B](fa: Tell[W, A])(f: A => B): Tell[W, B] = fa.map(f)
    }
    implicit def writerFunctor[W] = new Functor[[A] = Writer[W, A]] {
    def map[A, B](fa: Writer[W, A])(f: A => B): Writer[W, B] = fa.map(f)
    }
    'VODUPSͷܕΫϥεΛ࣮૷͢Δඞཁ͕͋Δ

    View Slide

  28. 'SFF8SJUFS
    type Writer[W, A] = Free[[T] = Tell[W, T], A]
    case class Tell[W, A](w: W, a: A) {
    def map[B](f: A => B) = Tell(w, f(a))
    }
    def tell[W](w: W): Writer[W, Unit] =
    Free.lift[[T] = Tell[W, T], Unit](Tell(w, ()))
    implicit def tellFunctor[W] = new Functor[[A] = Tell[W, A]] {
    def map[A, B](fa: Tell[W, A])(f: A => B): Tell[W, B] = fa.map(f)
    }
    implicit def writerFunctor[W] = new Functor[[A] = Writer[W, A]] {
    def map[A, B](fa: Writer[W, A])(f: A => B): Writer[W, B] = fa.map(f)
    }
    def runAsList[W, A](free: Writer[W, A]): (List[W], A) =
    free match {
    case pure: Free.Pure[({type F[T] = Tell[W, T]})#F, A] => (Nil, pure.a)
    case impure: Free.Impure[({type F[T] = Tell[W, T]})#F, A] =>
    runAsList(impure.ff.a) match {
    case (ws, a) => (impure.ff.w :: ws, a)
    }
    }
    val e = for {
    _ _ } yield ()
    runAsList(e)
    // (List(hoge, fuga),())

    View Slide

  29. 'SFF.BZCF
    type ConstUnit[A] = Unit
    type Maybe[A] = Free[ConstUnit, A]
    def some[A](a: A): Maybe[A] = Free.Pure[ConstUnit, A](a)
    def none[A]: Maybe[A] = Free.Impure[ConstUnit, A]((): ConstUnit[Maybe[A]])
    def safeDiv(n: Int, d: Int): Maybe[Int] = if (d == 0) none else some(n / d)
    implicit val ConstUnitFunctor = new Functor[ConstUnit] {
    def map[A, B](fa: ConstUnit[A])(f: A => B): ConstUnit[B] = (): ConstUnit[B]
    }
    val r = for {
    n m } yield m
    def maybe[A](maybe: Maybe[A])(default: A): A = maybe match {
    case Pure(a) => a
    case Impure(()) => default
    }
    assert(maybe(r)(42) == 42) // r͕noneͳͷͰɺdefaultͷ42͕ద༻͞ΕΔ
    $POTU6OJU͕'VODUPSͳͷͰɺ
    ϞφυʹͳΔ

    View Slide

  30. 'SFFS.POBE
    'VODUPSͷ੍໿ͳ͠ʹϞφυʹͳΔ
    case class Pure[F[_], A](a: A) extends Freer[F, A]
    case class Impure[F[_], A, B](fa: F[A], f: A => Freer[F, B]) extends Freer[F, B]
    sealed trait Freer[F[_], A] {
    def map[B](f: A => B): Freer[F, B] = flatMap(a => Pure(f(a)))
    def flatMap[B](f: A => Freer[F, B]): Freer[F, B] =
    this match {
    case Pure(a) => f(a)
    case Impure(fa, g) => Impure(fa, (a: Any) => g(a).flatMap(f))
    }
    }
    object Freer {
    def lift[F[_], A](fa: F[A]): Freer[F, A] =
    Impure(fa, a => Pure[F, A](a))
    }
    $PZPOFEBͱΏ͏NBQΛ࣋ͭߏ଄Λ'SFFʹՃ͑ͨ΋ͷ

    View Slide

  31. 'SFFS8SJUFS
    type Writer[W, A] = Freer[[T] = Tell[W, T], A]
    case class Tell[W, A](w: W, a: A) {
    def map[B](f: A => B) = Tell(w, f(a))
    }
    def tell[W](w: W): Writer[W, Unit] =
    Freer.lift[[T] = Tell[W, T], Unit](Tell(w, ()))
    def runAsList[W, A, B](freer: Writer[W, A]): (List[W], A) =
    freer match {
    case pure: Freer.Pure[({type F[T] = Tell[W, T]})#F, A] => (Nil, pure.a)
    case impure: Freer.Impure[({type F[T] = Tell[W, T]})#F, A, B] =>
    runAsList(impure.k(impure.fa.a)) match {
    case (ws, a) => (impure.fa.w :: ws, a)
    }
    }
    val e = for {
    _ _ } yield ()
    runAsList(e)
    // (List(hoge, fuga),())
    8SJUFS͕'VODUPSͰͳͯ͘΋ɺ
    ϞφυʹͳΔ

    View Slide

  32. 'SFFS.BZCF
    type ConstUnit[A] = Unit
    type Maybe[A] = Freer[ConstUnit, A]
    def some[A](a: A): Maybe[A] = Pure[ConstUnit, A](a)
    def none[A]: Maybe[A] = Freer[ConstUnit, A]((): ConstUnit[Maybe[A]])
    def safeDiv(n: Int, d: Int): Maybe[Int] = if (d == 0) none else some(n / d)
    val r = for {
    n m } yield m
    def maybe[A](maybe: Maybe[A])(default: A): A = maybe match {
    case Pure(a) => a
    case Impure((), _) => default
    }
    assert(maybe(r)(42) == 42) // r͕noneͳͷͰɺdefaultͷ42͕ద༻͞ΕΔ
    $POTU6OJU͕'VODUPSͰͳͯ͘΋ɺ
    ϞφυʹͳΔ

    View Slide

  33. 0QFO6OJPO
    'SFFSͰఆٛͨ͠ϞφυΛ૊ΈΘͤΒΕͳ͍͔ʁ
    ܕͷ࿨Λ'SFFSʹ༩͑Δ
    cc
    6OJPOΛ࢖ͬͨ'SFFS
    cc
    &YUFOTJCMF&⒎FDUT
    ྫ8SJUFS3FBEFS

    View Slide

  34. 0QFO6OJPO
    sealed trait Union
    // ܕͷऴ୺Λද͢
    sealed trait Void extends Union
    // ܕͷ࿨Λߏ੒͢Δ
    sealed trait :+:[F[_], U case class Inl[F[_], A, U case class Inr[F[_], U type ListOrOption = Option :+: List :+: Void
    val option1: ListOrOption = Inr(Inl(List(1, 2)))
    ܕͷ࿨Λ࣮ݱ͢Δ

    View Slide

  35. .FNCFS
    trait Member[F[_], U // ϞφυΛߏ੒͢ΔF͔ΒUnionΛಘΔ
    def inject[A](f: F[A]): U
    }
    // ࠨଆ΁ͷຒΊࠐΈ
    implicit def left[F[_], U new Member[F, F :+: U] {
    def inject[A](f: F[A]): F :+: U = Inl(f)
    }
    // ӈଆ΁ͷຒΊࠐΈ
    implicit def right[F[_], G[_], U Member[F, G :+: U] =
    new Member[F, G :+: U] {
    def inject[A](f: F[A]): G :+: U = Inr(member.inject(f))
    }
    6OJPO΁஋ΛຒΊࠐΉͨΊͷܕΫϥε
    type ListOrOption = Option :+: List :+: Void
    val option1: ListOrOption = Inr(Inl(List(1, 2)))
    val option2: ListOrOption = Member[List, ListOrOption].inject(List(1, 2))

    View Slide

  36. &YUFOTJCMF&⒎FDUT
    trait Eff[U def map[B](f: A => B): Eff[U, B] = flatMap(a => Pure(f(a)))
    def flatMap[B](f: A => Eff[U, B]): Eff[U, B] =
    this match {
    case Pure(a) => f(a)
    case Impure(u, g) => Impure(u, g :+ f)
    }
    }
    case class Pure[U case class Impure[U ܕύϥϝʔλʹ6OJPOΛ࣋ͭ

    View Slide

  37. &⒎8SJUFS
    case class Writer[W](w: W)
    type U = Writer :+: Void
    implicit val w = Member[Writer, U]
    def tell[U Eff.Impure(ev.inject(Writer(w)), Leaf((_: Any) => Eff.Pure(())))
    def runWriter[U eff match {
    case Eff.Pure(a) => Eff.Pure((Nil, a))
    case Eff.Impure(Inl(Writer(w: W)), k) => runWriter[U, W, A](k(w)) map {
    case (ws, a) => (w :: ws, a)
    }
    case Eff.Impure(Inr(r), k) => Eff.Impure(r, Leaf((a: Any) => runWriter(k(a))))
    }

    View Slide

  38. &⒎3FBEFS
    case class Reader[I]()
    type U = Reader :+: Void
    implicit val r = Member[Reader, U]
    def ask[U Eff.lift[U, Reader, I](Reader[I])
    def runReader[U eff match {
    case Eff.Pure(a) => Eff.Pure(a)
    case Eff.Impure(Inl(Reader()), k) => runReader(k(i), i)
    case Eff.Impure(Inr(r), k) => Eff.Impure(r, Leaf((a: Any) => runReader(k(a), i)))
    }

    View Slide

  39. 8SJUFS3FBEFS
    def run[A](eff: Eff[Void, A]): A =
    eff match {
    case Eff.Pure(a) => a
    }
    def e[U for {
    _ x _ } yield x
    type MonadStack = Reader :+: Writer :+: Void
    Eff.run(runWriter(runReader(e[MonadStack], 1)))
    // (List(2, 2),1))
    ϞφυελοΫ
    ೋͭͷϞφυΛҰͭͷGPSࣜʹॻ͚Δ
    SVO3FBEFS SVO8SJUFS
    ҕৡ
    BTLϦΫΤετΛॲཧ UFMMϦΫΤετΛॲཧ
    QVSFͳܭࢉʹͳͬͨΒɺ
    SVOͰ݁ՌΛऔΓग़͢

    View Slide

  40. &⒎͕ղܾ͢Δ͜ͱ
    ߹੒͢ΔϞφυ͕૿͑Δͨͼʹɺܭࢉͷޮ཰͕མͪΔ
    ԼҐͷϞφυͷॲཧΛߦ͏ͷʹɺҰʑMJGUΛߦ͏ඞཁ͕͋Δ
    Ϟφυͷ߹੒ॱ͸ݻఆ͞Ε͍ͯͯɺ్தͰೖΕସ͑Δ͜ͱ͕Ͱ͖ͳ͍
    ϞφυΛ߹੒͢Δॱ൪ʹΑͬͯɺܭࢉͷҙຯ͕มΘΔ
    Ϟφυม׵ࢠͷ໰୊Λղܾ͢Δख๏

    View Slide

  41. &⒎͕ղܾ͢Δ͜ͱ
    ߹੒͢ΔϞφυ͕૿͑Δͨͼʹɺܭࢉͷޮ཰͕མͪΔ
    ԼҐͷϞφυͷॲཧΛߦ͏ͷʹɺҰʑMJGUΛߦ͏ඞཁ͕͋Δ
    def e[U for {
    _ x _ } yield x
    ɾճϧʔϓ͕૸Βͳ͍
    ɾMJGUΛߦ͏ඞཁ͕ͳ͍

    View Slide

  42. &⒎͕ղܾ͢Δ͜ͱ
    def e[U for {
    _ x _ } yield x
    type MonadStack1 = Reader :+: Writer :+: Void
    type MonadStack2 = Writer :+: Reader :+: Void
    assert(Eff.run(runWriter(runReader(e[MonadStack1], 1))) == (List(2, 2),1))
    assert(Eff.run(runReader(runWriter(e[MonadStack2]), 1)) == (List(2, 2),1))
    Ϟφυͷ߹੒ॱ͸ݻఆ͞Ε͍ͯͯɺ్தͰೖΕସ͑Δ͜ͱ͕Ͱ͖ͳ͍
    ϞφυΛ߹੒͢Δॱ൪ʹΑͬͯɺܭࢉͷҙຯ͕มΘΔ
    ݺͼग़͢ଆͰ੍ޚ͢Δ

    View Slide

  43. 6OJPO5ZQF
    val x: String | Int =
    if util.Random.nextBoolean() then "hoge" else 0
    EPUUZͩͱ6OJPO5ZQF͕දݱ͠΍͍͢
    IUUQTXXXTMJEFTIBSFOFU4BOTIJSP:PTIJEBFYUFOTJCMFF⒎FDUTJOEPUUZ>

    View Slide

  44. &YUFOTJCMF&⒎FDUTJO%PUUZ
    val e: Eff[[T] => Reader[Int, T] | Writer[Int, T], Int] =
    for {
    x _ } yield x
    scala> run(runWriter(runReader(e, 0)))
    val res0: (Int, Int) = (1,0)
    ΑΓγϯϓϧͳهड़͕Մೳʹͳͬͨ
    def e[U IUUQTXXXTMJEFTIBSFOFU4BOTIJSP:PTIJEBFYUFOTJCMFF⒎FDUTJOEPUUZ>

    View Slide

  45. Benchmarks
    Ϟφυม׵ࢠͱ&⒎ͷϕϯνϚʔΫͷൺֱ͸ɺ
    ݩࢿྉʹࡌ͍ͬͯΔͷͰͦͪΒΛӾཡ͍ͩ͘͞
    IUUQTXXXTMJEFTIBSFOFU4BOTIJSP:PTIJEBFYUFOTJCMFF⒎FDUTJOEPUUZ

    View Slide

  46. ·ͱΊ
    ɾϞφυελοΫ͸ɺϞφυม׵ࢠͷ໰୊Λղܾ͢Δ
    ɾ࣮૷͕ෳࡶɺɺ
    ɾ&YUFOTJCMF&⒎FDUT͸ϞφυΛҕৡؔ܎Ͱ
    දݱ͢Δ͜ͱʹΑͬͯɺϞφυελοΫΛ࣮ݱ͢Δ

    View Slide

  47. ࢀߟจݙ
    IUUQTLPOOTBODPNQSPHIBTLFMMFYUFOTJCMFF⒎FDUTIUNM
    ˒ &YUFOTJCMF&⒎FDUT͸Ϟφυม׵ࢠʹର͢ΔٹੈओʹͳΓಘΔ͔ʁ
    IUUQIBMDBUPSHTDBMBFYUFOTJCMF
    ˒ &YUFOTJCMF&⒎FDUTJO4DBMB
    ˒ Freer Monads, More Extensible Effects
    IUUQTXXXTMJEFTIBSFOFULPOOGSFFSNPOBETNPSFFYUFOTJCMFF⒎FDUT

    View Slide