SlideShare una empresa de Scribd logo
1 de 74
Descargar para leer sin conexión
Extensible Effects
in Dotty
SanshiroYoshida @halcat0x15a
DWANGO Co.,Ltd.
Contents
• Dotty
• Introduction of language features
• Extensible Effects
• Explanation of the implementation
DottyとExtEffについて話します
About Dotty
• A next generation compiler for Scala
• Formalized in DOT
• Implemented new features
Dottyは次世代のScalaコンパイラです
DOT
• Dependent Object Types
• A calculus aimed as a new foundation of
Scala
• Featured path-dependent types, refinement
types, and abstract type members
DOTはScalaの基礎となる計算モデルです。
DOT
• Models Scala language features with
minimal calculus.
trait List { self =>
type A
def head: self.A; def tail: List { type A <: self.A }
}
def cons(x: { type A })(hd: x.A)(tl: List { type A <:
x.A }): List { type A <: x.A } =
new List { self =>
type A = x.A
def head = hd; def tail = tl
}
DOTは最小限の計算でScalaの言語機能をモデル化します
New language features
• Enums
• Type Lambdas
• Intersection Types
• Union Types
• Implicit Function Types
• etc.
Dottyの新しい言語機能です
Enums
• Syntax sugar for enumerations and ADTs.
• The companion object defines utility
methods.
enumは列挙型と代数的データ型を定義するための構文です
Enums
• The value of enums is tagged with Int.
enum Color {
case Red, Green, Blue
}
scala> Color.enumValue(0)
val res0: Color = Red
列挙型の値にはInt型のタグが付けられます
Enums
• The `enum` supports ADTs.
• ADTs can define fields and methods.
enumキーワードは代数的データ型をサポートします
enum Option[+A] {
case Some(a: A)
case None
def isEmpty: Boolean = this == None
}
Type Lambdas
• Representation of higher-kinded types.
Type lambdaは高階型を表現します
type Pair = [A] => (A, A)
val p: Pair[Int] = (0, 1)
Type Lambdas
• Possible to write partial application of type
directly
型の部分適用を直接書けるようになりました
// Scala2
type FreeMonad[F[_]] =
Monad[({ type λ[A] = Free[F, A] })#λ]
// Dotty
type FreeMonad[F[_]] = Monad[[A] => Free[F, A]]
Dotty
• More expressive types
• More easy-to-write syntax
• More suitable for functional programming
Dottyは関数型プログラミングにより適しています
About ExtEff
• Extensible Effects = Freer Monad + Open
Union + Type-aligned Queue
• Freer Monad = Free Monad + Free Functor
(Coyoneda)
• I will talk about these abstractions.
今日はこれらの抽象概念について話します
Monad
• Monad is a computation with side-effects.
• For example, Option monad is a
computation for which there may not exist
a value.
• You can write it procedurally with ‘for’
expression.
モナドは副作用付き計算のこと
Free
• Free f is a monad if f is a functor.
• Various monads can be represented using f.
Freeはファンクタによって様々なモナドを表現できます
Definition of Free
Pureは純粋な計算でImpureは副作用付きの計算を表します
• Pure is a pure computation.
• Impure is a computation with side-effects.
enum Free[F[_], A] {
case Pure(a: A)
case Impure(ffree: F[Free[F, A]])
}
def lift(fa: F[A])(implicit F: Functor[F]): Free[F, A] =
Impure(F.map(fa)(a => Pure(a)))
Free Monad
• flatMap has the constraint that F is Functor
flatMapはFがFunctorである制約を持ちます
enum Free[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(ffree) =>
F.map(ffree)(free => free.flatMap(f))
}
}
Free Writer
• Writer is a computation with another
output.
• For example, it is a computation that
outputs logs.
Writerは別の出力を持つ計算です
Free Writer
• Definition of Writer monad by Free.
FreeによるWriterモナドの定義です
type Writer[W, A] = Free[[T] => Tell[W, T], A]
// Effect is described CPS
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(Tell(w, ()))
Free Writer
• An example of handler for Writer.
• Writer can output as List.
WriterはListとして出力することができます
def runAsList[W, A](free: Writer[W, A]): (List[W], A) =
free match {
case Free.Pure(a) => (Nil, a)
case Free.Impure(Tell(w, free)) =>
runAsList(free).map {
case (ws, a) => (w :: ws, a)
}
}
Free Writer
• Writer can output asVector.
WriterはVectorとしても出力できます
def runAsVec[W, A](free: Writer[W, A]): (Vector[W], A) =
{
def go(acc: Vector[W], free: Writer[W, A]):
(Vector[W], A) =
free match {
case Free.Pure(a) => (acc, a)
case Free.Impure(Tell(w, free)) =>
go(acc :+ w, free)
}
go(Vector.empty, free)
}
Free Writer
• Multiple interpretations can be made for
one expression.
一つの式に対して複数の解釈が可能です
val e = for {
_ <- tell("hoge")
_ <- tell("fuga")
} yield ()
scala> runAsList(e)
val res0: (List[String], Unit) = (List(hoge, fuga),())
scala> runAsVec(e)
val res1: (Vector[String], Unit) = (Vector(hoge, fuga),
())
Free
• Free represents various monads.
• Free has a functor constraint.
• Free is free to interpret.
Freeは様々なモナドを表現でき、自由に解釈できます
Freer
• Freer is Free applied to Coyoneda.
• Freer becomes a monad without
constraints.
• Freer uses a tree in flatMap.
Freerは制約なしにモナドになります
Coyoneda
• Coyoneda is Free Functor.
• For all f, Coyoneda f is a functor.
任意fについてCoyoneda fはファンクタです
Definition of Coyoneda
• FMap has a signature similar to map.
FMapはmapと似たシグネチャをもちます
enum Coyoneda[F[_], A] {
case FMap[F[_], A, B](fa: F[A], k: A => B) extends
Coyoneda[F, B]
}
def lift[F[_], A](fa: F[A]): Coyoneda[F, A] =
Coyoneda.FMap(fa, a => a)
Coyoneda Functor
• Coyoneda becomes a functor without
constraints.
Coyonedaは制約なしにファンクタになります
enum Coyoneda[F[_], A] {
def map[B](f: A => B): Coyoneda[F, B] =
this match {
case Coyoneda.FMap(fi, k) =>
Coyoneda.FMap(fi, k andThen f)
}
}
Coyoneda
• Using Coyoneda seems to be able to map
everything.
Coyonedaは全てをmapできるように見えます
case class Box[A](a: A)
val box = Coyoneda.lift(Box(0))
.map(i => i + 1)
.map(i => i.toString)
Coyoneda
• Coyoneda does not apply to the value of
the Box.
• Coyoneda#map is only composing
functions.
Coyonedaは関数の合成をしているだけで適用をしていません
Definition of Freer
• Expands the definition of Free Coyoneda.
• Impure has a signature similar to flatMap.
Free Coyonedaの定義を展開したものです
enum Freer[F[_], A] {
case Pure(a: A)
case Impure[F[_], A, B](fa: F[A], k: A => Freer[F, B])
extends Freer[F, B]
}
def lift[F[_], A](fa: F[A]): Freer[F, A] =
Impure(fa, a => Pure(a))
Freer Monad
• flatMap is a free from constraints of
Functor.
flatMapからFunctorの制約がなくなりました
enum Freer[F[_], A] {
def flatMap[B](f: A => Freer[F, B]): Freer[F, B] =
this match {
case Freer.Pure(a) => f(a)
case Freer.Impure(fa, k) =>
Freer.Impure(fa, a => k(a).flatMap(f))
}
}
Freer Monad
• This implementation of flatMap is slow.
• flatMap(f_0).flatMap(f_1)…flatMap(f_n) is
O(n^2).
このflatMapの実装は遅いです
Type-aligned Queue
• FTCQ is a sequence of functions.
• It is implemented with a tree.
FTCQは関数の列を表します
val `A => F[C]`: FTCQ[F, A, C] =
Node(
Leaf(f: A => F[B]),
Leaf(g: B => F[C])
)
Type-aligned Queue
• The composition of functions is constant-
time.
• The application of function is stack-safe.
合成は定数時間で、適用はスタックセーフに行われます
val `A => F[D]`: FTCQ[F, A, D] =
Node(
`A => F[C]`,
Leaf(h: C => F[D])
)
Definition of Fast Freer
• Impure represents a continuation with
FTCQ.
Impureは継続をFTCQで表現します
type Arrs[F, A, B] = FTCQ[[T] => Freer[F, T], A, B]
enum Freer[F[_], A] {
case Pure(a: A)
case Impure[F[_], A, B](fa: F[A], k: Arrs[F, A, B])
extends Freer[F, B]
}
Fast Freer Monad
• flatMap is constant-time.
flatMapは定数時間で実行されます
enum Freer[F[_], A] {
def flatMap[B](f: A => Freer[F, B]): Freer[F, B] =
this match {
case Freer.Pure(a) => f(a)
case Freer.Impure(fa, k) =>
Freer.Impure(fa, k :+ f)
}
}
Freer Reader
• Reader is a computation with environment.
• For example, it is a computation that takes
the configuration.
Readerは環境を持つような計算です
Freer Reader
• Definition of Reader monad by Freer.
FreerによるReaderモナドの定義です
type Reader[I, A] = Freer[[T] => Ask[I, T], A]
case class Ask[I, A](k: I => A)
def ask[I]: Reader[I, I] =
Freer.lift(Ask(i => i))
Freer Reader
• The handler of Freer applies continuation.
Freerのハンドラは継続の適用を行います
def runReader[I, A](freer: Reader[I, A], i: I): A =
freer match {
case Freer.Pure(a) => a
case Freer.Impure(Ask(f), k) =>
runReader(k(f(i)), i)
}
Freer Reader
• An example of a Reader monad.
Readerモナドの例です
val e = for {
x <- ask[Int]
y <- ask[Int]
} yield x + y
scala> runReader(e, 1)
val res0: Int = 2
Freer
• Freer has no constraints of Functor.
• Freer is faster than Free by using Type-
aligned Queue.
FreerはFunctorの制約がなくFreeよりも高速です
Extensible Effects
• ExtEff is Freer applied to Open Union.
• ExtEff can compose various effects using
Open Union.
ExtEffはOpen Unionを使って様々な副作用を合成できます
Open Union
• Representation of extensible sum of types
• Automatic construction by typeclass
Open Unionは拡張可能な型の和を表します
Open Union
• Union seems to be a higher-kinded type
version of Either.
Unionは高階型を使ったEitherのような定義です
enum Union[F[_], G[_], A] {
case Inl(value: F[A])
case Inr(value: G[A])
}
Open Union
• An alias for writing in infix notation is
useful.
中置記法で記述するための別名があると便利です
type :+:[F[_], G[_]] = [A] => Union[F, G, A]
type ListOrOption = List :+: Option :+: Nothing
Member
MemberはUnionに値をinjectします
trait Member[F[_], R[_]] {
def inject[A](fa: F[A]): R[A]
}
• Member injects a value into an union.
Member
• It is uniquely derived if a value is in Inl.
値がInlにあることでインスタンスを一意に導出できます
implicit def leftMember[F[_], G[_]] =
new Member[F, F :+: G] {
def inject[A](fa: F[A]) = Union.Inl(fa)
}
implicit def rightMember[F[_], G[_], H[_]](implicit F:
Member[F, H]) =
new Member[F, G :+: H] {
def inject[A](fa: F[A]) = Union.Inr(F.inject(fa))
}
Member
• An example of constructing Union using
Member.
Memberを使ってUnionを構成する例です
def inject[F[_], R[_], A](fa: F[A])(implicit F:
Member[F, R]): R[A] =
F.inject(fa)
scala> val opt: ListOrOption[Int] = inject(Option(0))
val opt: ListOrOption[Int] = Inr(Inl(Some(0)))
Definition of ExtEff
• lift injects effects using Member.
liftはMemberを使ってエフェクトを注入します
enum Eff[R[_], A] {
case Pure(a: A)
case Impure[R[_], A, B](union: R[A], k: Arrs[F, A, B])
extends Eff[R, B]
}
def lift[F[_], R[_], A](fa: F[A])(implicit F: Member[F,
R]): Eff[R, A] =
Impure(F.inject(fa), Arrs(a => Pure(a)))
ExtEff Writer
コンストラクタからモナドの値が決まります
• No longer necessary to write in CPS.
• A value of a monad is determined from the
constructor.
enum Writer[W, A] {
case Tell[W](w: W) extends Writer[W, Unit]
}
def tell[R[_], W](w: W)(implicit ev: Member[[A] =>
Writer[W, A], R]): Eff[R, Unit] = Eff.lift(Tell(w))
ExtEff Reader
プリミティブの関数はコンストラクタを持ち上げるだけです
• Primitive functions only lifts constructors.
enum Reader[I, A] {
case Ask[I]() extends Reader[I, I]
}
def ask[R[_], I](implicit ev: Member[[A] => Reader[I,
A], R]): Eff[R, I] = Eff.lift(Ask[I])
ExtEff Reader
• If another effect appears, transfer it.
他のエフェクトがあらわれた場合は処理を移譲します
def runReader[R[_], I, A](eff: Eff[([T] => Reader[I, T])
:+: R, A], i: I): Eff[R, A] =
eff match {
case Eff.Pure(a) => Free.Pure(a)
case Eff.Impure(Union.Inl(Reader.Ask()), k) =>
runReader(k(i), i)
case Eff.Impure(Union.Inr(r), k) =>
Eff.Impure(r, a => runReader(k(a), i))
}
ExtEff Handler
• Handlers can be generalized.
ハンドラは一般化することができます
def handleRelay[F[_], R[_], A, B]
(eff: Eff[F :+: R, A])
(pure: A => Eff[R, B])
(bind: F[A] => (A => Eff[R, B]) => Eff[R, B])
: Eff[R, B] = eff match {
case Eff.Pure(a) => pure(a)
case Eff.Impure(Union.Inl(fa), k) =>
bind(fa)(a => handleRelay(k(a))(pure)(bind))
case Eff.Impure(Union.Inr(r), k) =>
Eff.Impure(r, a => handleRelay(k(a))(pure)(bind))
}
ExtEff Writer
• Just write pure and flatMap with a handler.
handleRelayを使えばpureとflatMapを書くだけです。
def runWriter[R[_], W, A](eff: Eff[([T] => Writer[W, T])
:+: R, A]): Eff[R, (List[W], A)] =
handleRelay(eff)(a => (Nil, a)) {
case Writer.Tell(w) =>
k => k(()).map { case (ws, a) => (w :: ws, a) }
}
Run ExtEff
• If effects is Nothing, no instance of Impure
exists.
def run[A](eff: Eff[Nothing, A]): A =
eff match {
case Eff.Pure(a) => a
}
エフェクトがNothingならImpureのインスタンスは存在しない
ExtEff Example
• You can write two monads in one ‘for’
二つのモナドを一つのfor式に書けます
def e[R[_]](implicit r: Member[[T] => Reader[Int, T],
R], w: Member[[T] => Writer[Int, T], R]): Eff[R, Int] =
for {
x <- Reader.ask
_ <- Writer.tell(x + 1)
} yield x
ExtEff Example
• To run the Eff requires explicit monad stack
実行にはエフェクトスタックの明示が必要です
type Stack = ([T] => Reader[Int, T]) :+: ([T] =>
Writer[Int, T]) :+: Nothing
scala> run(runWriter(runReader(e[Stack], 0))))
val res0: (List[Int], Int) = (List(1),0)
Problems of ExtEff
• Requires description of type parameters
• We can not make use of type inference.
型パラメータを引き回す必要があります
ExtEff with Subtyping
• Make type parameters covariant.
• Replace Open Union with Dotty’s Union
types.
Open UnionをDottyのUnion typesで置き換えます
Union types
• Values of type A | B are all values of type A
and type B
A ¦ BはAとBの値すべてをとります
val x: String | Int =
if util.Random.nextBoolean() then "hoge" else 0
Tagged Union
• Tagged Union is tagged to identify the value
of Union types.
Tagged Unionは値を識別するためにタグが付けられます
case class Union[+A](tag: Tag[_], value: A)
object Union {
def apply[F[_], A](value: F[A])(implicit F: Tag[F]) =
new Union(F, value)
}
Tag
• Tag is implemented with ClassTag.
• It makes unique identifiers from types.
case class Tag[F[_]](value: String)
object Tag {
implicit def __[F[_, _], T](implicit F: ClassTag[F[_,
_]], T: ClassTag[T]): Tag[[A] => F[T, A]] =
Tag(s"${F}[${T}, _]")
}
型から一意な識別子を作ります
New ExtEff
• The type parameter R becomes covariant.
• Impure is replaced Open Union with Tagged
Union.
ImpureはOpen UnionをTagged Unionで置き換えます
enum Eff[+R[_], A] {
case Pure(a: A)
case Impure[R[_], A, B](union: Union[R[A]], k: Arrs[R,
A, B]) extends Eff[R, B]
}
def lift[F[_]: Tag, A](fa: F[A]): Eff[F, A] =
Impure(Union(fa), a => Pure(a))
New ExtEff
• flatMap returns an union of effects.
flatMapはエフェクトの和を返します
enum Eff[+R[_], A] {
def flatMap[S[_], B](f: A => Eff[S, B])
: Eff[[T] => R[T] | S[T], B] =
this match {
case Eff.Pure(a) => f(a)
case Eff.Impure(u, k) =>
Eff.Impure(u, k :+ f)
}
}
New Handler
• Uses Tag to identify an effect.
Tagを使ってエフェクトを識別します
def handleRelay[F[_], R[_], A, B]
(eff: Eff[[T] => F[T] | R[T], A])
(pure: A => Eff[R, B])
(flatMap: F[A] => (A => Eff[R, B]) => Eff[R, B])
(implicit F: Tag[F]): Eff[R, B] =
eff match {
case Eff.Pure(a) => pure(a)
case Eff.Impure(Union(`F`, fa: F[A]), k) =>
flatMap(fa)(a => handleRelay(k(a))(pure)(flatMap))
case Eff.Impure(u: Union[R[A]], k) =>
Eff.Impure(r, a => handleRelay(k(a))(pure)(flatMap))
}
New ExtEff Example
• You can write more simply.
• Type inference works.
よりシンプルな記述が可能になりました
val e: Eff[[T] => Reader[Int, T] | Writer[Int, T], Int]
=
for {
x <- Reader.ask[Int]
_ <- Writer.tell(x + 1)
} yield x
scala> run(runWriter(runReader(e, 0)))
val res0: (Int, Int) = (1,0)
Benchmarks
• Comparison of ExtEff and
MonadTransformer.
• Count up with State monad in 1,000,000
loops.
• The effect stack gets deeper.
ExtEffとMTを比較します
Benchmarks in ExtEff
def benchEff(ns: Seq[Int])
: Eff[[A] => State[Int, A], Int] =
ns.foldLeft(Eff.Pure(1)) { (acc, n) =>
if n % 5 == 0 then for {
acc <- acc
s <- Reader.ask[Int]
_ <- Writer.tell(s + 1)
} yield acc max n
else acc.map(_ max n)
}
ExtEffのベンチマークコードです
Benchmarks in MT
MTのベンチマークコードです
def benchTrans[F[_]: Monad](ns: Seq[Int])
: StateT[F, Int, Int] = {
val m = StateT.stateTMonadState[Int, F]
ns.foldLeft(StateT.stateT(1)) { (acc, n) =>
if n % 5 == 0 then for {
acc <- acc
s <- m.get
_ <- m.put(s + 1)
} yield acc max n
else acc.map(_ max n)
}
}
Benchmarks
• Overlays State effects
Stateモナドを重ねます
def benchEff(): (Int, Int) =
Eff.run(State.run(0)(Bench.benchEff(1 to N)))
def benchEffS(): (String, (Int, Int)) =
Eff.run(State.run("")(State.run(0)(Bench.benchEff(1 to
N))))
def benchTrans(): (Int, Int) =
Bench.benchTrans[Id](1 to N).runRec(0)
def benchTransS(): (String, (Int, Int)) =
Bench.benchTrans[[A] => StateT[Id, String, A]](1 to
N).runRec(0).runRec("")
Benchmarks
• Run JMH with 20 warmups,100 iterations.
ExtEffの実行は線形時間、MTの実行は二乗時間です
Benchmark Mode Cnt Score Error Units
BenchJmh.benchEffJmh thrpt 100 5.724 ± 0.220 ops/s
BenchJmh.benchEffSJmh thrpt 100 5.133 ± 0.154 ops/s
BenchJmh.benchEffSSJmh thrpt 100 4.578 ± 0.175 ops/s
BenchJmh.benchTransJmh thrpt 100 4.928 ± 0.155 ops/s
BenchJmh.benchTransSJmh thrpt 100 1.848 ± 0.107 ops/s
BenchJmh.benchTransSSJmh thrpt 100 0.852 ± 0.042 ops/s
Benchmarks
• The run-time of ExtEff is linear.
• The run-time of MT is quadratic.
ExtEffはUnion Typesを使うことでシンプルにかけます
ops/s
0
1.5
3
4.5
6
ExtEff MT
Conclusions
• You can compose multiple effects by ExtEff.
• Using the union types makes writing ExtEff
simpler.
• If the monad stack is deep, ExtEff is faster
than MT.
ExtEffはUnion Typesを使うことでシンプルにかけます
Thank you for listening

Más contenido relacionado

La actualidad más candente

ホモトピー型理論入門
ホモトピー型理論入門ホモトピー型理論入門
ホモトピー型理論入門k h
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~Nobuhisa Koizumi
 
2.2 limits ii
2.2 limits ii2.2 limits ii
2.2 limits iimath265
 
Extensible Eff Applicative
Extensible Eff ApplicativeExtensible Eff Applicative
Extensible Eff ApplicativeSanshiro Yoshida
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門Hideyuki Tanaka
 
2 integration and the substitution methods x
2 integration and the substitution methods x2 integration and the substitution methods x
2 integration and the substitution methods xmath266
 
php-src の歩き方
php-src の歩き方php-src の歩き方
php-src の歩き方do_aki
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Scott Wlaschin
 
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldFunctional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldJorge Vásquez
 
Race condition
Race conditionRace condition
Race conditionhama7230
 
Effective modern c++ 8
Effective modern c++ 8Effective modern c++ 8
Effective modern c++ 8uchan_nos
 
モナドハンズオン前座
モナドハンズオン前座モナドハンズオン前座
モナドハンズオン前座bleis tift
 
F#によるFunctional Programming入門
F#によるFunctional Programming入門F#によるFunctional Programming入門
F#によるFunctional Programming入門bleis tift
 
自動定理証明の紹介
自動定理証明の紹介自動定理証明の紹介
自動定理証明の紹介Masahiro Sakai
 
私を SKI に連れてって
私を SKI に連れてって私を SKI に連れてって
私を SKI に連れてってSusisu
 
続・モジュール / Introduction to C++ modules (part 2)
続・モジュール / Introduction to C++ modules (part 2)続・モジュール / Introduction to C++ modules (part 2)
続・モジュール / Introduction to C++ modules (part 2)TetsuroMatsumura
 
Why functional programming and category theory strongly matters
Why functional programming and category theory strongly mattersWhy functional programming and category theory strongly matters
Why functional programming and category theory strongly mattersPiotr Paradziński
 

La actualidad más candente (20)

ホモトピー型理論入門
ホモトピー型理論入門ホモトピー型理論入門
ホモトピー型理論入門
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~
 
2.2 limits ii
2.2 limits ii2.2 limits ii
2.2 limits ii
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
 
Comonads in Haskell
Comonads in HaskellComonads in Haskell
Comonads in Haskell
 
Extensible Eff Applicative
Extensible Eff ApplicativeExtensible Eff Applicative
Extensible Eff Applicative
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
2 integration and the substitution methods x
2 integration and the substitution methods x2 integration and the substitution methods x
2 integration and the substitution methods x
 
php-src の歩き方
php-src の歩き方php-src の歩き方
php-src の歩き方
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
Functional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorldFunctional Programming 101 with Scala and ZIO @FunctionalWorld
Functional Programming 101 with Scala and ZIO @FunctionalWorld
 
Race condition
Race conditionRace condition
Race condition
 
Effective modern c++ 8
Effective modern c++ 8Effective modern c++ 8
Effective modern c++ 8
 
モナドハンズオン前座
モナドハンズオン前座モナドハンズオン前座
モナドハンズオン前座
 
F#によるFunctional Programming入門
F#によるFunctional Programming入門F#によるFunctional Programming入門
F#によるFunctional Programming入門
 
Monadic Java
Monadic JavaMonadic Java
Monadic Java
 
自動定理証明の紹介
自動定理証明の紹介自動定理証明の紹介
自動定理証明の紹介
 
私を SKI に連れてって
私を SKI に連れてって私を SKI に連れてって
私を SKI に連れてって
 
続・モジュール / Introduction to C++ modules (part 2)
続・モジュール / Introduction to C++ modules (part 2)続・モジュール / Introduction to C++ modules (part 2)
続・モジュール / Introduction to C++ modules (part 2)
 
Why functional programming and category theory strongly matters
Why functional programming and category theory strongly mattersWhy functional programming and category theory strongly matters
Why functional programming and category theory strongly matters
 

Similar a Extensible Effects in Dotty

Functional programming with FSharp
Functional programming with FSharpFunctional programming with FSharp
Functional programming with FSharpDaniele Pozzobon
 
The Swift Compiler and Standard Library
The Swift Compiler and Standard LibraryThe Swift Compiler and Standard Library
The Swift Compiler and Standard LibrarySantosh Rajan
 
Intro f# functional_programming
Intro f# functional_programmingIntro f# functional_programming
Intro f# functional_programmingMauro Ghiani
 
Basic concept of Python.pptx includes design tool, identifier, variables.
Basic concept of Python.pptx includes design tool, identifier, variables.Basic concept of Python.pptx includes design tool, identifier, variables.
Basic concept of Python.pptx includes design tool, identifier, variables.supriyasarkar38
 
Under the hood of scala implicits (kl10tch 10.03.2015)
Under the hood of scala implicits (kl10tch 10.03.2015)Under the hood of scala implicits (kl10tch 10.03.2015)
Under the hood of scala implicits (kl10tch 10.03.2015)Alexander Podkhalyuzin
 
Scala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsScala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsKirill Kozlov
 
modul-python-all.pptx
modul-python-all.pptxmodul-python-all.pptx
modul-python-all.pptxYusuf Ayuba
 
Functional IO and Effects
Functional IO and EffectsFunctional IO and Effects
Functional IO and EffectsDylan Forciea
 
Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverseLuka Jacobowitz
 
Advance Scala - Oleg Mürk
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg MürkPlanet OS
 
Using Language Oriented Programming to Execute Computations on the GPU
Using Language Oriented Programming to Execute Computations on the GPUUsing Language Oriented Programming to Execute Computations on the GPU
Using Language Oriented Programming to Execute Computations on the GPUSkills Matter
 
INTRODUCTION TO PYTHON.pptx
INTRODUCTION TO PYTHON.pptxINTRODUCTION TO PYTHON.pptx
INTRODUCTION TO PYTHON.pptxNimrahafzal1
 

Similar a Extensible Effects in Dotty (20)

Functional programming with FSharp
Functional programming with FSharpFunctional programming with FSharp
Functional programming with FSharp
 
The Swift Compiler and Standard Library
The Swift Compiler and Standard LibraryThe Swift Compiler and Standard Library
The Swift Compiler and Standard Library
 
From DOT to Dotty
From DOT to DottyFrom DOT to Dotty
From DOT to Dotty
 
F# 101
F# 101F# 101
F# 101
 
Intro f# functional_programming
Intro f# functional_programmingIntro f# functional_programming
Intro f# functional_programming
 
Gnu octave
Gnu octave Gnu octave
Gnu octave
 
Basic concept of Python.pptx includes design tool, identifier, variables.
Basic concept of Python.pptx includes design tool, identifier, variables.Basic concept of Python.pptx includes design tool, identifier, variables.
Basic concept of Python.pptx includes design tool, identifier, variables.
 
Clojure intro
Clojure introClojure intro
Clojure intro
 
Under the hood of scala implicits (kl10tch 10.03.2015)
Under the hood of scala implicits (kl10tch 10.03.2015)Under the hood of scala implicits (kl10tch 10.03.2015)
Under the hood of scala implicits (kl10tch 10.03.2015)
 
Should i Go there
Should i Go thereShould i Go there
Should i Go there
 
Python ppt
Python pptPython ppt
Python ppt
 
Scala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsScala. Introduction to FP. Monads
Scala. Introduction to FP. Monads
 
Frp2016 3
Frp2016 3Frp2016 3
Frp2016 3
 
Function
FunctionFunction
Function
 
modul-python-all.pptx
modul-python-all.pptxmodul-python-all.pptx
modul-python-all.pptx
 
Functional IO and Effects
Functional IO and EffectsFunctional IO and Effects
Functional IO and Effects
 
Oh, All the things you'll traverse
Oh, All the things you'll traverseOh, All the things you'll traverse
Oh, All the things you'll traverse
 
Advance Scala - Oleg Mürk
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg Mürk
 
Using Language Oriented Programming to Execute Computations on the GPU
Using Language Oriented Programming to Execute Computations on the GPUUsing Language Oriented Programming to Execute Computations on the GPU
Using Language Oriented Programming to Execute Computations on the GPU
 
INTRODUCTION TO PYTHON.pptx
INTRODUCTION TO PYTHON.pptxINTRODUCTION TO PYTHON.pptx
INTRODUCTION TO PYTHON.pptx
 

Último

Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 

Último (20)

Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 

Extensible Effects in Dotty

  • 1. Extensible Effects in Dotty SanshiroYoshida @halcat0x15a DWANGO Co.,Ltd.
  • 2. Contents • Dotty • Introduction of language features • Extensible Effects • Explanation of the implementation DottyとExtEffについて話します
  • 3. About Dotty • A next generation compiler for Scala • Formalized in DOT • Implemented new features Dottyは次世代のScalaコンパイラです
  • 4. DOT • Dependent Object Types • A calculus aimed as a new foundation of Scala • Featured path-dependent types, refinement types, and abstract type members DOTはScalaの基礎となる計算モデルです。
  • 5. DOT • Models Scala language features with minimal calculus. trait List { self => type A def head: self.A; def tail: List { type A <: self.A } } def cons(x: { type A })(hd: x.A)(tl: List { type A <: x.A }): List { type A <: x.A } = new List { self => type A = x.A def head = hd; def tail = tl } DOTは最小限の計算でScalaの言語機能をモデル化します
  • 6. New language features • Enums • Type Lambdas • Intersection Types • Union Types • Implicit Function Types • etc. Dottyの新しい言語機能です
  • 7. Enums • Syntax sugar for enumerations and ADTs. • The companion object defines utility methods. enumは列挙型と代数的データ型を定義するための構文です
  • 8. Enums • The value of enums is tagged with Int. enum Color { case Red, Green, Blue } scala> Color.enumValue(0) val res0: Color = Red 列挙型の値にはInt型のタグが付けられます
  • 9. Enums • The `enum` supports ADTs. • ADTs can define fields and methods. enumキーワードは代数的データ型をサポートします enum Option[+A] { case Some(a: A) case None def isEmpty: Boolean = this == None }
  • 10. Type Lambdas • Representation of higher-kinded types. Type lambdaは高階型を表現します type Pair = [A] => (A, A) val p: Pair[Int] = (0, 1)
  • 11. Type Lambdas • Possible to write partial application of type directly 型の部分適用を直接書けるようになりました // Scala2 type FreeMonad[F[_]] = Monad[({ type λ[A] = Free[F, A] })#λ] // Dotty type FreeMonad[F[_]] = Monad[[A] => Free[F, A]]
  • 12. Dotty • More expressive types • More easy-to-write syntax • More suitable for functional programming Dottyは関数型プログラミングにより適しています
  • 13. About ExtEff • Extensible Effects = Freer Monad + Open Union + Type-aligned Queue • Freer Monad = Free Monad + Free Functor (Coyoneda) • I will talk about these abstractions. 今日はこれらの抽象概念について話します
  • 14. Monad • Monad is a computation with side-effects. • For example, Option monad is a computation for which there may not exist a value. • You can write it procedurally with ‘for’ expression. モナドは副作用付き計算のこと
  • 15. Free • Free f is a monad if f is a functor. • Various monads can be represented using f. Freeはファンクタによって様々なモナドを表現できます
  • 16. Definition of Free Pureは純粋な計算でImpureは副作用付きの計算を表します • Pure is a pure computation. • Impure is a computation with side-effects. enum Free[F[_], A] { case Pure(a: A) case Impure(ffree: F[Free[F, A]]) } def lift(fa: F[A])(implicit F: Functor[F]): Free[F, A] = Impure(F.map(fa)(a => Pure(a)))
  • 17. Free Monad • flatMap has the constraint that F is Functor flatMapはFがFunctorである制約を持ちます enum Free[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(ffree) => F.map(ffree)(free => free.flatMap(f)) } }
  • 18. Free Writer • Writer is a computation with another output. • For example, it is a computation that outputs logs. Writerは別の出力を持つ計算です
  • 19. Free Writer • Definition of Writer monad by Free. FreeによるWriterモナドの定義です type Writer[W, A] = Free[[T] => Tell[W, T], A] // Effect is described CPS 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(Tell(w, ()))
  • 20. Free Writer • An example of handler for Writer. • Writer can output as List. WriterはListとして出力することができます def runAsList[W, A](free: Writer[W, A]): (List[W], A) = free match { case Free.Pure(a) => (Nil, a) case Free.Impure(Tell(w, free)) => runAsList(free).map { case (ws, a) => (w :: ws, a) } }
  • 21. Free Writer • Writer can output asVector. WriterはVectorとしても出力できます def runAsVec[W, A](free: Writer[W, A]): (Vector[W], A) = { def go(acc: Vector[W], free: Writer[W, A]): (Vector[W], A) = free match { case Free.Pure(a) => (acc, a) case Free.Impure(Tell(w, free)) => go(acc :+ w, free) } go(Vector.empty, free) }
  • 22. Free Writer • Multiple interpretations can be made for one expression. 一つの式に対して複数の解釈が可能です val e = for { _ <- tell("hoge") _ <- tell("fuga") } yield () scala> runAsList(e) val res0: (List[String], Unit) = (List(hoge, fuga),()) scala> runAsVec(e) val res1: (Vector[String], Unit) = (Vector(hoge, fuga), ())
  • 23. Free • Free represents various monads. • Free has a functor constraint. • Free is free to interpret. Freeは様々なモナドを表現でき、自由に解釈できます
  • 24. Freer • Freer is Free applied to Coyoneda. • Freer becomes a monad without constraints. • Freer uses a tree in flatMap. Freerは制約なしにモナドになります
  • 25. Coyoneda • Coyoneda is Free Functor. • For all f, Coyoneda f is a functor. 任意fについてCoyoneda fはファンクタです
  • 26. Definition of Coyoneda • FMap has a signature similar to map. FMapはmapと似たシグネチャをもちます enum Coyoneda[F[_], A] { case FMap[F[_], A, B](fa: F[A], k: A => B) extends Coyoneda[F, B] } def lift[F[_], A](fa: F[A]): Coyoneda[F, A] = Coyoneda.FMap(fa, a => a)
  • 27. Coyoneda Functor • Coyoneda becomes a functor without constraints. Coyonedaは制約なしにファンクタになります enum Coyoneda[F[_], A] { def map[B](f: A => B): Coyoneda[F, B] = this match { case Coyoneda.FMap(fi, k) => Coyoneda.FMap(fi, k andThen f) } }
  • 28. Coyoneda • Using Coyoneda seems to be able to map everything. Coyonedaは全てをmapできるように見えます case class Box[A](a: A) val box = Coyoneda.lift(Box(0)) .map(i => i + 1) .map(i => i.toString)
  • 29. Coyoneda • Coyoneda does not apply to the value of the Box. • Coyoneda#map is only composing functions. Coyonedaは関数の合成をしているだけで適用をしていません
  • 30. Definition of Freer • Expands the definition of Free Coyoneda. • Impure has a signature similar to flatMap. Free Coyonedaの定義を展開したものです enum Freer[F[_], A] { case Pure(a: A) case Impure[F[_], A, B](fa: F[A], k: A => Freer[F, B]) extends Freer[F, B] } def lift[F[_], A](fa: F[A]): Freer[F, A] = Impure(fa, a => Pure(a))
  • 31. Freer Monad • flatMap is a free from constraints of Functor. flatMapからFunctorの制約がなくなりました enum Freer[F[_], A] { def flatMap[B](f: A => Freer[F, B]): Freer[F, B] = this match { case Freer.Pure(a) => f(a) case Freer.Impure(fa, k) => Freer.Impure(fa, a => k(a).flatMap(f)) } }
  • 32. Freer Monad • This implementation of flatMap is slow. • flatMap(f_0).flatMap(f_1)…flatMap(f_n) is O(n^2). このflatMapの実装は遅いです
  • 33. Type-aligned Queue • FTCQ is a sequence of functions. • It is implemented with a tree. FTCQは関数の列を表します val `A => F[C]`: FTCQ[F, A, C] = Node( Leaf(f: A => F[B]), Leaf(g: B => F[C]) )
  • 34. Type-aligned Queue • The composition of functions is constant- time. • The application of function is stack-safe. 合成は定数時間で、適用はスタックセーフに行われます val `A => F[D]`: FTCQ[F, A, D] = Node( `A => F[C]`, Leaf(h: C => F[D]) )
  • 35. Definition of Fast Freer • Impure represents a continuation with FTCQ. Impureは継続をFTCQで表現します type Arrs[F, A, B] = FTCQ[[T] => Freer[F, T], A, B] enum Freer[F[_], A] { case Pure(a: A) case Impure[F[_], A, B](fa: F[A], k: Arrs[F, A, B]) extends Freer[F, B] }
  • 36. Fast Freer Monad • flatMap is constant-time. flatMapは定数時間で実行されます enum Freer[F[_], A] { def flatMap[B](f: A => Freer[F, B]): Freer[F, B] = this match { case Freer.Pure(a) => f(a) case Freer.Impure(fa, k) => Freer.Impure(fa, k :+ f) } }
  • 37. Freer Reader • Reader is a computation with environment. • For example, it is a computation that takes the configuration. Readerは環境を持つような計算です
  • 38. Freer Reader • Definition of Reader monad by Freer. FreerによるReaderモナドの定義です type Reader[I, A] = Freer[[T] => Ask[I, T], A] case class Ask[I, A](k: I => A) def ask[I]: Reader[I, I] = Freer.lift(Ask(i => i))
  • 39. Freer Reader • The handler of Freer applies continuation. Freerのハンドラは継続の適用を行います def runReader[I, A](freer: Reader[I, A], i: I): A = freer match { case Freer.Pure(a) => a case Freer.Impure(Ask(f), k) => runReader(k(f(i)), i) }
  • 40. Freer Reader • An example of a Reader monad. Readerモナドの例です val e = for { x <- ask[Int] y <- ask[Int] } yield x + y scala> runReader(e, 1) val res0: Int = 2
  • 41. Freer • Freer has no constraints of Functor. • Freer is faster than Free by using Type- aligned Queue. FreerはFunctorの制約がなくFreeよりも高速です
  • 42. Extensible Effects • ExtEff is Freer applied to Open Union. • ExtEff can compose various effects using Open Union. ExtEffはOpen Unionを使って様々な副作用を合成できます
  • 43. Open Union • Representation of extensible sum of types • Automatic construction by typeclass Open Unionは拡張可能な型の和を表します
  • 44. Open Union • Union seems to be a higher-kinded type version of Either. Unionは高階型を使ったEitherのような定義です enum Union[F[_], G[_], A] { case Inl(value: F[A]) case Inr(value: G[A]) }
  • 45. Open Union • An alias for writing in infix notation is useful. 中置記法で記述するための別名があると便利です type :+:[F[_], G[_]] = [A] => Union[F, G, A] type ListOrOption = List :+: Option :+: Nothing
  • 46. Member MemberはUnionに値をinjectします trait Member[F[_], R[_]] { def inject[A](fa: F[A]): R[A] } • Member injects a value into an union.
  • 47. Member • It is uniquely derived if a value is in Inl. 値がInlにあることでインスタンスを一意に導出できます implicit def leftMember[F[_], G[_]] = new Member[F, F :+: G] { def inject[A](fa: F[A]) = Union.Inl(fa) } implicit def rightMember[F[_], G[_], H[_]](implicit F: Member[F, H]) = new Member[F, G :+: H] { def inject[A](fa: F[A]) = Union.Inr(F.inject(fa)) }
  • 48. Member • An example of constructing Union using Member. Memberを使ってUnionを構成する例です def inject[F[_], R[_], A](fa: F[A])(implicit F: Member[F, R]): R[A] = F.inject(fa) scala> val opt: ListOrOption[Int] = inject(Option(0)) val opt: ListOrOption[Int] = Inr(Inl(Some(0)))
  • 49. Definition of ExtEff • lift injects effects using Member. liftはMemberを使ってエフェクトを注入します enum Eff[R[_], A] { case Pure(a: A) case Impure[R[_], A, B](union: R[A], k: Arrs[F, A, B]) extends Eff[R, B] } def lift[F[_], R[_], A](fa: F[A])(implicit F: Member[F, R]): Eff[R, A] = Impure(F.inject(fa), Arrs(a => Pure(a)))
  • 50. ExtEff Writer コンストラクタからモナドの値が決まります • No longer necessary to write in CPS. • A value of a monad is determined from the constructor. enum Writer[W, A] { case Tell[W](w: W) extends Writer[W, Unit] } def tell[R[_], W](w: W)(implicit ev: Member[[A] => Writer[W, A], R]): Eff[R, Unit] = Eff.lift(Tell(w))
  • 51. ExtEff Reader プリミティブの関数はコンストラクタを持ち上げるだけです • Primitive functions only lifts constructors. enum Reader[I, A] { case Ask[I]() extends Reader[I, I] } def ask[R[_], I](implicit ev: Member[[A] => Reader[I, A], R]): Eff[R, I] = Eff.lift(Ask[I])
  • 52. ExtEff Reader • If another effect appears, transfer it. 他のエフェクトがあらわれた場合は処理を移譲します def runReader[R[_], I, A](eff: Eff[([T] => Reader[I, T]) :+: R, A], i: I): Eff[R, A] = eff match { case Eff.Pure(a) => Free.Pure(a) case Eff.Impure(Union.Inl(Reader.Ask()), k) => runReader(k(i), i) case Eff.Impure(Union.Inr(r), k) => Eff.Impure(r, a => runReader(k(a), i)) }
  • 53. ExtEff Handler • Handlers can be generalized. ハンドラは一般化することができます def handleRelay[F[_], R[_], A, B] (eff: Eff[F :+: R, A]) (pure: A => Eff[R, B]) (bind: F[A] => (A => Eff[R, B]) => Eff[R, B]) : Eff[R, B] = eff match { case Eff.Pure(a) => pure(a) case Eff.Impure(Union.Inl(fa), k) => bind(fa)(a => handleRelay(k(a))(pure)(bind)) case Eff.Impure(Union.Inr(r), k) => Eff.Impure(r, a => handleRelay(k(a))(pure)(bind)) }
  • 54. ExtEff Writer • Just write pure and flatMap with a handler. handleRelayを使えばpureとflatMapを書くだけです。 def runWriter[R[_], W, A](eff: Eff[([T] => Writer[W, T]) :+: R, A]): Eff[R, (List[W], A)] = handleRelay(eff)(a => (Nil, a)) { case Writer.Tell(w) => k => k(()).map { case (ws, a) => (w :: ws, a) } }
  • 55. Run ExtEff • If effects is Nothing, no instance of Impure exists. def run[A](eff: Eff[Nothing, A]): A = eff match { case Eff.Pure(a) => a } エフェクトがNothingならImpureのインスタンスは存在しない
  • 56. ExtEff Example • You can write two monads in one ‘for’ 二つのモナドを一つのfor式に書けます def e[R[_]](implicit r: Member[[T] => Reader[Int, T], R], w: Member[[T] => Writer[Int, T], R]): Eff[R, Int] = for { x <- Reader.ask _ <- Writer.tell(x + 1) } yield x
  • 57. ExtEff Example • To run the Eff requires explicit monad stack 実行にはエフェクトスタックの明示が必要です type Stack = ([T] => Reader[Int, T]) :+: ([T] => Writer[Int, T]) :+: Nothing scala> run(runWriter(runReader(e[Stack], 0)))) val res0: (List[Int], Int) = (List(1),0)
  • 58. Problems of ExtEff • Requires description of type parameters • We can not make use of type inference. 型パラメータを引き回す必要があります
  • 59. ExtEff with Subtyping • Make type parameters covariant. • Replace Open Union with Dotty’s Union types. Open UnionをDottyのUnion typesで置き換えます
  • 60. Union types • Values of type A | B are all values of type A and type B A ¦ BはAとBの値すべてをとります val x: String | Int = if util.Random.nextBoolean() then "hoge" else 0
  • 61. Tagged Union • Tagged Union is tagged to identify the value of Union types. Tagged Unionは値を識別するためにタグが付けられます case class Union[+A](tag: Tag[_], value: A) object Union { def apply[F[_], A](value: F[A])(implicit F: Tag[F]) = new Union(F, value) }
  • 62. Tag • Tag is implemented with ClassTag. • It makes unique identifiers from types. case class Tag[F[_]](value: String) object Tag { implicit def __[F[_, _], T](implicit F: ClassTag[F[_, _]], T: ClassTag[T]): Tag[[A] => F[T, A]] = Tag(s"${F}[${T}, _]") } 型から一意な識別子を作ります
  • 63. New ExtEff • The type parameter R becomes covariant. • Impure is replaced Open Union with Tagged Union. ImpureはOpen UnionをTagged Unionで置き換えます enum Eff[+R[_], A] { case Pure(a: A) case Impure[R[_], A, B](union: Union[R[A]], k: Arrs[R, A, B]) extends Eff[R, B] } def lift[F[_]: Tag, A](fa: F[A]): Eff[F, A] = Impure(Union(fa), a => Pure(a))
  • 64. New ExtEff • flatMap returns an union of effects. flatMapはエフェクトの和を返します enum Eff[+R[_], A] { def flatMap[S[_], B](f: A => Eff[S, B]) : Eff[[T] => R[T] | S[T], B] = this match { case Eff.Pure(a) => f(a) case Eff.Impure(u, k) => Eff.Impure(u, k :+ f) } }
  • 65. New Handler • Uses Tag to identify an effect. Tagを使ってエフェクトを識別します def handleRelay[F[_], R[_], A, B] (eff: Eff[[T] => F[T] | R[T], A]) (pure: A => Eff[R, B]) (flatMap: F[A] => (A => Eff[R, B]) => Eff[R, B]) (implicit F: Tag[F]): Eff[R, B] = eff match { case Eff.Pure(a) => pure(a) case Eff.Impure(Union(`F`, fa: F[A]), k) => flatMap(fa)(a => handleRelay(k(a))(pure)(flatMap)) case Eff.Impure(u: Union[R[A]], k) => Eff.Impure(r, a => handleRelay(k(a))(pure)(flatMap)) }
  • 66. New ExtEff Example • You can write more simply. • Type inference works. よりシンプルな記述が可能になりました val e: Eff[[T] => Reader[Int, T] | Writer[Int, T], Int] = for { x <- Reader.ask[Int] _ <- Writer.tell(x + 1) } yield x scala> run(runWriter(runReader(e, 0))) val res0: (Int, Int) = (1,0)
  • 67. Benchmarks • Comparison of ExtEff and MonadTransformer. • Count up with State monad in 1,000,000 loops. • The effect stack gets deeper. ExtEffとMTを比較します
  • 68. Benchmarks in ExtEff def benchEff(ns: Seq[Int]) : Eff[[A] => State[Int, A], Int] = ns.foldLeft(Eff.Pure(1)) { (acc, n) => if n % 5 == 0 then for { acc <- acc s <- Reader.ask[Int] _ <- Writer.tell(s + 1) } yield acc max n else acc.map(_ max n) } ExtEffのベンチマークコードです
  • 69. Benchmarks in MT MTのベンチマークコードです def benchTrans[F[_]: Monad](ns: Seq[Int]) : StateT[F, Int, Int] = { val m = StateT.stateTMonadState[Int, F] ns.foldLeft(StateT.stateT(1)) { (acc, n) => if n % 5 == 0 then for { acc <- acc s <- m.get _ <- m.put(s + 1) } yield acc max n else acc.map(_ max n) } }
  • 70. Benchmarks • Overlays State effects Stateモナドを重ねます def benchEff(): (Int, Int) = Eff.run(State.run(0)(Bench.benchEff(1 to N))) def benchEffS(): (String, (Int, Int)) = Eff.run(State.run("")(State.run(0)(Bench.benchEff(1 to N)))) def benchTrans(): (Int, Int) = Bench.benchTrans[Id](1 to N).runRec(0) def benchTransS(): (String, (Int, Int)) = Bench.benchTrans[[A] => StateT[Id, String, A]](1 to N).runRec(0).runRec("")
  • 71. Benchmarks • Run JMH with 20 warmups,100 iterations. ExtEffの実行は線形時間、MTの実行は二乗時間です Benchmark Mode Cnt Score Error Units BenchJmh.benchEffJmh thrpt 100 5.724 ± 0.220 ops/s BenchJmh.benchEffSJmh thrpt 100 5.133 ± 0.154 ops/s BenchJmh.benchEffSSJmh thrpt 100 4.578 ± 0.175 ops/s BenchJmh.benchTransJmh thrpt 100 4.928 ± 0.155 ops/s BenchJmh.benchTransSJmh thrpt 100 1.848 ± 0.107 ops/s BenchJmh.benchTransSSJmh thrpt 100 0.852 ± 0.042 ops/s
  • 72. Benchmarks • The run-time of ExtEff is linear. • The run-time of MT is quadratic. ExtEffはUnion Typesを使うことでシンプルにかけます ops/s 0 1.5 3 4.5 6 ExtEff MT
  • 73. Conclusions • You can compose multiple effects by ExtEff. • Using the union types makes writing ExtEff simpler. • If the monad stack is deep, ExtEff is faster than MT. ExtEffはUnion Typesを使うことでシンプルにかけます
  • 74. Thank you for listening