SlideShare a Scribd company logo
1 of 74
Download to read offline
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

More Related Content

What's hot

Fake It Outside-In TDD @XP2017
Fake It Outside-In TDD @XP2017Fake It Outside-In TDD @XP2017
Fake It Outside-In TDD @XP2017David Völkel
 
OpenFOAM を用いた Adjoint 形状最適化事例1
OpenFOAM を用いた Adjoint 形状最適化事例1OpenFOAM を用いた Adjoint 形状最適化事例1
OpenFOAM を用いた Adjoint 形状最適化事例1Fumiya Nozaki
 
Capabilities for Resources and Effects
Capabilities for Resources and EffectsCapabilities for Resources and Effects
Capabilities for Resources and EffectsMartin Odersky
 
OpenFOAMに実装したS-CLSVOF法検証(静止気泡のLaplace圧)
OpenFOAMに実装したS-CLSVOF法検証(静止気泡のLaplace圧)OpenFOAMに実装したS-CLSVOF法検証(静止気泡のLaplace圧)
OpenFOAMに実装したS-CLSVOF法検証(静止気泡のLaplace圧)takuyayamamoto1800
 
磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!Ra Zon
 
Row-based Effect Systems for Algebraic Effect Handlers
Row-based Effect Systems for Algebraic Effect HandlersRow-based Effect Systems for Algebraic Effect Handlers
Row-based Effect Systems for Algebraic Effect HandlersTaro Sekiyama
 
ホモトピー型理論入門
ホモトピー型理論入門ホモトピー型理論入門
ホモトピー型理論入門k h
 
関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐりKazuyuki TAKASE
 
すごい配列楽しく学ぼう
すごい配列楽しく学ぼうすごい配列楽しく学ぼう
すごい配列楽しく学ぼうxenophobia__
 
Effective Modern C++ 勉強会#7 Item 27
Effective Modern C++ 勉強会#7 Item 27Effective Modern C++ 勉強会#7 Item 27
Effective Modern C++ 勉強会#7 Item 27Mitsuru Kariya
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?Moriharu Ohzu
 
モナドハンズオン前座
モナドハンズオン前座モナドハンズオン前座
モナドハンズオン前座bleis tift
 
Ad hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and CatsAd hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and CatsPhilip Schwarz
 
インタフェースの実装パターン
インタフェースの実装パターンインタフェースの実装パターン
インタフェースの実装パターンTakuya Ueda
 
入門Transducers
入門Transducers入門Transducers
入門Transducerssohta
 
いまさらながらの Windows Workflow 入門
いまさらながらの Windows Workflow 入門いまさらながらの Windows Workflow 入門
いまさらながらの Windows Workflow 入門Jun-ichi Sakamoto
 
ラムダ計算入門
ラムダ計算入門ラムダ計算入門
ラムダ計算入門Eita Sugimoto
 

What's hot (20)

Fake It Outside-In TDD @XP2017
Fake It Outside-In TDD @XP2017Fake It Outside-In TDD @XP2017
Fake It Outside-In TDD @XP2017
 
OpenFOAM を用いた Adjoint 形状最適化事例1
OpenFOAM を用いた Adjoint 形状最適化事例1OpenFOAM を用いた Adjoint 形状最適化事例1
OpenFOAM を用いた Adjoint 形状最適化事例1
 
Capabilities for Resources and Effects
Capabilities for Resources and EffectsCapabilities for Resources and Effects
Capabilities for Resources and Effects
 
Comonads in Haskell
Comonads in HaskellComonads in Haskell
Comonads in Haskell
 
OpenFOAMに実装したS-CLSVOF法検証(静止気泡のLaplace圧)
OpenFOAMに実装したS-CLSVOF法検証(静止気泡のLaplace圧)OpenFOAMに実装したS-CLSVOF法検証(静止気泡のLaplace圧)
OpenFOAMに実装したS-CLSVOF法検証(静止気泡のLaplace圧)
 
磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!
 
Row-based Effect Systems for Algebraic Effect Handlers
Row-based Effect Systems for Algebraic Effect HandlersRow-based Effect Systems for Algebraic Effect Handlers
Row-based Effect Systems for Algebraic Effect Handlers
 
ホモトピー型理論入門
ホモトピー型理論入門ホモトピー型理論入門
ホモトピー型理論入門
 
関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり
 
すごい配列楽しく学ぼう
すごい配列楽しく学ぼうすごい配列楽しく学ぼう
すごい配列楽しく学ぼう
 
Effective Modern C++ 勉強会#7 Item 27
Effective Modern C++ 勉強会#7 Item 27Effective Modern C++ 勉強会#7 Item 27
Effective Modern C++ 勉強会#7 Item 27
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
 
モナドハンズオン前座
モナドハンズオン前座モナドハンズオン前座
モナドハンズオン前座
 
Ad hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and CatsAd hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and Cats
 
インタフェースの実装パターン
インタフェースの実装パターンインタフェースの実装パターン
インタフェースの実装パターン
 
入門Transducers
入門Transducers入門Transducers
入門Transducers
 
いまさらながらの Windows Workflow 入門
いまさらながらの Windows Workflow 入門いまさらながらの Windows Workflow 入門
いまさらながらの Windows Workflow 入門
 
圏とHaskellの型
圏とHaskellの型圏とHaskellの型
圏とHaskellの型
 
Applicative Functor
Applicative FunctorApplicative Functor
Applicative Functor
 
ラムダ計算入門
ラムダ計算入門ラムダ計算入門
ラムダ計算入門
 

Similar to 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 to 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
 

Recently uploaded

The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...AliaaTarek5
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Scott Andery
 

Recently uploaded (20)

The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
 

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