SlideShare a Scribd company logo
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

ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022
Alexander Ioffe
 
Revisiting Combinators
Revisiting CombinatorsRevisiting Combinators
Revisiting Combinators
Edward Kmett
 
Operators in C/C++
Operators in C/C++Operators in C/C++
Operators in C/C++
Shobi P P
 
Haskell study 4
Haskell study 4Haskell study 4
Haskell study 4
Nam Hyeonuk
 
Quill vs Slick Smackdown
Quill vs Slick SmackdownQuill vs Slick Smackdown
Quill vs Slick Smackdown
Alexander Ioffe
 
Ch02 fuzzyrelation
Ch02 fuzzyrelationCh02 fuzzyrelation
Ch02 fuzzyrelation
Hoàng Đức
 
Monads do not Compose
Monads do not ComposeMonads do not Compose
Monads do not Compose
Philip Schwarz
 
Haskell study 5
Haskell study 5Haskell study 5
Haskell study 5
Nam Hyeonuk
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Philip Schwarz
 
Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2
Philip Schwarz
 
Cartesian Closed Category
Cartesian Closed CategoryCartesian Closed Category
Cartesian Closed Category
Sosuke MORIGUCHI
 
Celery의 빛과 그림자
Celery의 빛과 그림자Celery의 빛과 그림자
Celery의 빛과 그림자
Minyoung Jeong
 
Fs2 - Crash Course
Fs2 - Crash CourseFs2 - Crash Course
Fs2 - Crash Course
Lukasz Byczynski
 
純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門
Kimikazu Kato
 
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
Philip Schwarz
 
Divisor
DivisorDivisor
Divisoroupc
 
Oracle Management Cloud サービス概要説明資料
Oracle Management Cloud サービス概要説明資料Oracle Management Cloud サービス概要説明資料
Oracle Management Cloud サービス概要説明資料
オラクルエンジニア通信
 
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
Jorge Vásquez
 
C++ references
C++ referencesC++ references
C++ references
corehard_by
 

What's hot (20)

ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022
 
Revisiting Combinators
Revisiting CombinatorsRevisiting Combinators
Revisiting Combinators
 
Operators in C/C++
Operators in C/C++Operators in C/C++
Operators in C/C++
 
Haskell study 4
Haskell study 4Haskell study 4
Haskell study 4
 
Quill vs Slick Smackdown
Quill vs Slick SmackdownQuill vs Slick Smackdown
Quill vs Slick Smackdown
 
Ch02 fuzzyrelation
Ch02 fuzzyrelationCh02 fuzzyrelation
Ch02 fuzzyrelation
 
Monads do not Compose
Monads do not ComposeMonads do not Compose
Monads do not Compose
 
Haskell study 5
Haskell study 5Haskell study 5
Haskell study 5
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2
 
Cartesian Closed Category
Cartesian Closed CategoryCartesian Closed Category
Cartesian Closed Category
 
Celery의 빛과 그림자
Celery의 빛과 그림자Celery의 빛과 그림자
Celery의 빛과 그림자
 
Fs2 - Crash Course
Fs2 - Crash CourseFs2 - Crash Course
Fs2 - Crash Course
 
純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門
 
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
 
TaPL9
TaPL9TaPL9
TaPL9
 
Divisor
DivisorDivisor
Divisor
 
Oracle Management Cloud サービス概要説明資料
Oracle Management Cloud サービス概要説明資料Oracle Management Cloud サービス概要説明資料
Oracle Management Cloud サービス概要説明資料
 
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
 
C++ references
C++ referencesC++ references
C++ references
 

Similar to Extensible Effects in Dotty

Functional programming with FSharp
Functional programming with FSharpFunctional programming with FSharp
Functional programming with FSharp
Daniele Pozzobon
 
The Swift Compiler and Standard Library
The Swift Compiler and Standard LibraryThe Swift Compiler and Standard Library
The Swift Compiler and Standard Library
Santosh Rajan
 
From DOT to Dotty
From DOT to DottyFrom DOT to Dotty
From DOT to Dotty
Martin Odersky
 
F# 101
F# 101F# 101
F# 101
Chris Alcock
 
Intro f# functional_programming
Intro f# functional_programmingIntro f# functional_programming
Intro f# functional_programming
Mauro Ghiani
 
Gnu octave
Gnu octave Gnu octave
Gnu octave
Milad Nourizade
 
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
 
Should i Go there
Should i Go thereShould i Go there
Should i Go there
Shimi Bandiel
 
Python ppt
Python pptPython ppt
Python ppt
Anush verma
 
Scala. Introduction to FP. Monads
Scala. Introduction to FP. MonadsScala. Introduction to FP. Monads
Scala. Introduction to FP. Monads
Kirill Kozlov
 
Frp2016 3
Frp2016 3Frp2016 3
Frp2016 3
Kirill Kozlov
 
modul-python-all.pptx
modul-python-all.pptxmodul-python-all.pptx
modul-python-all.pptx
Yusuf Ayuba
 
Functional IO and Effects
Functional IO and EffectsFunctional IO and Effects
Functional IO and Effects
Dylan 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 traverse
Luka Jacobowitz
 
Advance Scala - Oleg Mürk
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg Mürk
Planet 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 GPU
Skills Matter
 
INTRODUCTION TO PYTHON.pptx
INTRODUCTION TO PYTHON.pptxINTRODUCTION TO PYTHON.pptx
INTRODUCTION TO PYTHON.pptx
Nimrahafzal1
 

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

FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
mikeeftimakis1
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
Matthew Sinclair
 
Free Complete Python - A step towards Data Science
Free Complete Python - A step towards Data ScienceFree Complete Python - A step towards Data Science
Free Complete Python - A step towards Data Science
RinaMondal9
 
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Nexer Digital
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
ThomasParaiso2
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems S.M.S.A.
 
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
James Anderson
 
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
Peter Spielvogel
 
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
Neo4j
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 

Recently uploaded (20)

FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
 
Free Complete Python - A step towards Data Science
Free Complete Python - A step towards Data ScienceFree Complete Python - A step towards Data Science
Free Complete Python - A step towards Data Science
 
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
 
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
 
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
 
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 

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