KEMBAR78
Intro to Functional Reactive Programming In Scala | PDF
Introduction to Functional Reactive
Programming with Scala
Diego E. Alonso
Scala eXchange 2018
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 1 / 29
What and Why?
What this talk is not about?
Any API or implementation of common Scala streaming libraries,
such as FS2, Scalaz-Stream, Monix, akka-streams
This talk is about
The Functional Reactive Programming paradigm, its inception,
concepts, arrows, a small implementation, relation to streams
Why do I care about FRP?
Unexpected applications for FP
FP lore: streams, monads, arrows
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 2 / 29
Reactive and Functional?
Transformational Programs are short-lived
Input
Program
Output
Takes all input before start
Starts and runs for some time
While running, neither takes input nor gives output
Terminates and give all output
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 3 / 29
Reactive and Functional?
Reactive Applications are Long-lived
Input
Program
Output
Runs for long time, never ends
Always takes new inputs
Always gives new output
Output depends on all past inputs
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 4 / 29
Reactive and Functional?
What is Functional Programming (simple answers)
Input
Program
Output
FP is programming with functions
Function: a computation that relates every input value to an
output value that is only determined by the input
Does not depend on mutable inner state
This denition looks very transformational
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 5 / 29
Reactive and Functional?
Reactive Applications are Stateful
Input
Program
Output
Does the past has real existence? Does the past exist
concretely? Is there somewhere or other a place, a world of
solid objects, where the past is still happening?
Past inputs only exists on the state
Present inputs changes that state
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 6 / 29
Reactive and Functional?
Reactive Applications care about timing
Input
Program
Output
Not just what inputs or outputs but also when
Output may feed back to input, in short time
But time is a side eect (clock)
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 7 / 29
Reactive and Functional?
What is Functional Programming?
FP is Declarative: what things are, not what they do
Denotational semantics: give meanings to programs
Domain: a world of ideas, or mathematical objects
An expression is just a name for an idea in domain
Compose meanings of composite expressions
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 8 / 29
Functional Reactive Programming
What does a Reactive Programming mean, functionally
Input
Program
Output
Entities in Domain can be innite or dense
We can see all input throug time as entity
All output of a program though run-time as one entity
A Reactive Program is map of input(t) to output(t)
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 9 / 29
Functional Reactive Programming
What's in a program in an FRP language?
X(t) +
Z(t)
F V (t)
G
Declarative approach to build reactive applications
An FRP program describes signals and signal functions
Signals are values that may vary over time
Signal functions show how signals depend on each other
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 10 / 29
Functional Reactive Programming
Interpretation of FRP program by sampling
X(t) +
Z(t)
F V (t)
G
To run an FRP program we need an interpreter
It builds a long stream of samples (with times)
Each signal function is run as a stream transformer
FRP splits time-sampling from continuous logic
Sample at the edge of the program
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 11 / 29
Arrowised Functional Reactive Programming
Simple FRP uses combinators of signals
X(t) +
Z(t)
F V (t)
G
Classic FRP works at the level of Signals: Sig[X]
Transform value of signal using function
Combine values of xed independent signals
Use value of signal to build another signal
Use value of signal to control which other signal follows
These is done with operations of Monad typeclass
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 12 / 29
Arrowised Functional Reactive Programming
Arrowised FRP: functions instead of signals
X(t) +
Z(t)
F V (t)
G
Arrowised FRP works only at level of Signal Functions (SF)
In AFRP, you start from some basic SFs
You combine them using Arrow operations
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 13 / 29
Arrowised Functional Reactive Programming
The Arrow Type Class
X(t) +
Z(t)
F V (t)
G
Monad is class for types F[V ] of values V in eect F,
it gives operations to make F-values from F-values
Arrow is class for types A[I, O] of A-functions from I to O
with operations to transform A-functions into A-functions
Mix A-functions into an A-function on tuples or eithers
Compose A-functions into a single one
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 14 / 29
From Lists to Monadic Stream Functions
Starting from a Scala List
sealed trait List[T]
case class Nil[T]() extends List[T]
case class Cons(head: T, tail: List[T]
The data type marks end or continuation
Backed by a data structure
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 15 / 29
From Lists to Monadic Stream Functions
Scala Lists as a trait with two methods
trait List[T] {
def head: Option[T]
def tail: Option[List[T]]
}
Methods need not be backed by data structure
The Option marks if it is the end of list
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 16 / 29
From Lists to Monadic Stream Functions
Lists as traits with a single methods
trait List[T] {
def uncons: Option[(T, List[T])]
}
trait InfList[T] {
def uncons: Id[(T, InfList[T])]
}
In eect, Option means may-terminate, and Id that not
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 17 / 29
From Lists to Monadic Stream Functions
Monadic Streams: generic sequence of eectful steps
trait MonSt[F[_], T] {
def uncons: F[(T, MonSt[F, T])]
}
Monadic streams are generic on the eect
The eect covers both the head and the tail of the stream
Instances of MonSt can include state, and pass new state in tail
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 18 / 29
Monadic Stream Functions
Denition of the Monadic Stream Functions trait
trait MoSF[F[_], In, Out] {
def apply(i: In): F[(Out, This)]
type This = MoSF[F, In, Out]
}
takes an input In, and runs computation in F
that returns value Out and a continuation
An instance of MoSF can have inner state
the instance of continuation has next state
Generalises lists, monadic streams, and sinks
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 19 / 29
Monadic Stream Functions
Basic and stateless MoSF
Basic constructors: make a MoSF[F, I, O] from
Value Type Function Type
Eectless pure O arr I ⇒ O
Eectful liftM F[O] arrM I ⇒ F[O]
pure is an MoSF that always returns given value
arr is an MoSF that always applies given function
liftM is an MoSF that always perform given F
arrM is an MoSF that applies given computation
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 20 / 29
Monadic Stream Functions
arr: return result of function
case class arr[F[_]: App, I, O]( fun: I = O)
extends MoSF[F, I, O] { self =
def apply(i: I): F[(O, This)] =
( fun(i) - self ).pure
}
case class liftM[F[_]: Functor, I, O](fo: F[O])
extends MoSF[F, I, O] { self =
def apply(i: I): F[(O, This)] =
fo.map( o = o - self )
}
// type This = MoSF[F, I, O]
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 21 / 29
Monadic Stream Functions
ap: merge input-wise two independent MoSF
def ap[F[_]: App, In, Mid, Out](
sffun: MoSF[F, In, Mid = O],
sfmid: MoSF[F, In, Mid]
): MoSF[F, In, Out] =
(i: In) = App[F].map2(sffun(i), sfmid(i)) {
case ( (fun, fkont), (arg, mkont) ) =
fun(arg) - ap(fkont, mkont)
}
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 22 / 29
Monadic Stream Functions
andThen: pass output to another MoSF
def andThen[F[_]: Monad, In, Mid, Out](
mosf: MoSF[F, In, Mid],
post: MoSF[F, Mid, Out]
): MoSF[F, In, Out] =
(i: In) = for {
(m, mosfK) - mosf(i)
(o, postK) - post(m)
} yield o - andThen(mosf, postK)
Continuation is composition of continuations
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 23 / 29
Monadic Stream Functions
rst: pair inputs and output of MoSF with extra
def first[F[_]: Functor, In, Out, eX](
mosf: MoSF[F, In, Out]
): MoSF[F, (In,eX), (Out,eX)] = {
case (i, x) =
mosf(i) map { case (o, cont) =
(o, x) - cont.first
}}
applies mosf to the rst element
pairs it with the second element
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 24 / 29
Monadic Stream Functions
left: handle case Left, pass Right through
case class left[F[_]: App, I, O, X](
mosf: MoSF[F, I, O]
) extends MoSF[F, I or X, O or X] { self =
def apply(iox: I or X): M[(O or X, This)] =
iox match {
case Right(x) =
(Right(x) - self).pure
case Left(i) = mosf(i).map {
case (o, cont) = Left(o) - cont.left
}
// type This = MoSF[I or X, O or X]
} // type or[A,B] = Either[A,B]
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 25 / 29
Monadic Stream Functions and Monadic Streams
Can we make a MoSF from Monadic Stream
trait MoSF[F[_], I, O] {
def apply(i: I): F[(O, MoSF[F, I, O])]
}
trait MoSt[G[_], T] {
def uncons: G[ (T, MoSt[G,T]) ]
}
// type MoSt[G[_], T] = MoSF[G, Unit, O]
// type MoSF[F[_], I, O] = MoSt[ ******* , *]
So, MoSt[G, T] is just a MoSF[G, Unit, T]
Can we make a MoSF on top of a MoST?
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 26 / 29
Monadic Stream Functions and Monadic Streams
YES, if we integrate the input into the eect of stream
trait MoSF[F[_], I, O] {
def apply(i: I): F[(O, MoSF[F, I, O])]
}
trait MoSt[G[_], T] {
def uncons: G[ (T, MoSt[G,T]) ]
}
// type MoSt[G[_], T] = MoSF[G, Unit, O]
// type MoSF[F[_], I, O] = MoSt[ Kl[F,I,?], O]
// type Kl[F[_], I, O] = I = F[O]
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 27 / 29
Summary
FRP is useful abstraction to describe reactive applications
Arrows is useful type-class for composing eectful computations
We can implement and use FRP in Scala
Next work: follow trend to do Monadic Stream Functions on FS2
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 28 / 29
Thank you to: I
Functional Reactive Programming, Refactored. Perez, Barenz,
Nilsson. Haskell Symposium, 2016.
Genuinely Functional User Interfaces. Courtney, Elliott.
The Essence and Origins of Functional Reactive Programming.
Elliott. LambdaJam 2015.
Diego E. Alonso Introduction to Functional Reactive Programming with Scala 29 / 29

Intro to Functional Reactive Programming In Scala

  • 1.
    Introduction to FunctionalReactive Programming with Scala Diego E. Alonso Scala eXchange 2018 Diego E. Alonso Introduction to Functional Reactive Programming with Scala 1 / 29
  • 2.
    What and Why? Whatthis talk is not about? Any API or implementation of common Scala streaming libraries, such as FS2, Scalaz-Stream, Monix, akka-streams This talk is about The Functional Reactive Programming paradigm, its inception, concepts, arrows, a small implementation, relation to streams Why do I care about FRP? Unexpected applications for FP FP lore: streams, monads, arrows Diego E. Alonso Introduction to Functional Reactive Programming with Scala 2 / 29
  • 3.
    Reactive and Functional? TransformationalPrograms are short-lived Input Program Output Takes all input before start Starts and runs for some time While running, neither takes input nor gives output Terminates and give all output Diego E. Alonso Introduction to Functional Reactive Programming with Scala 3 / 29
  • 4.
    Reactive and Functional? ReactiveApplications are Long-lived Input Program Output Runs for long time, never ends Always takes new inputs Always gives new output Output depends on all past inputs Diego E. Alonso Introduction to Functional Reactive Programming with Scala 4 / 29
  • 5.
    Reactive and Functional? Whatis Functional Programming (simple answers) Input Program Output FP is programming with functions Function: a computation that relates every input value to an output value that is only determined by the input Does not depend on mutable inner state This denition looks very transformational Diego E. Alonso Introduction to Functional Reactive Programming with Scala 5 / 29
  • 6.
    Reactive and Functional? ReactiveApplications are Stateful Input Program Output Does the past has real existence? Does the past exist concretely? Is there somewhere or other a place, a world of solid objects, where the past is still happening? Past inputs only exists on the state Present inputs changes that state Diego E. Alonso Introduction to Functional Reactive Programming with Scala 6 / 29
  • 7.
    Reactive and Functional? ReactiveApplications care about timing Input Program Output Not just what inputs or outputs but also when Output may feed back to input, in short time But time is a side eect (clock) Diego E. Alonso Introduction to Functional Reactive Programming with Scala 7 / 29
  • 8.
    Reactive and Functional? Whatis Functional Programming? FP is Declarative: what things are, not what they do Denotational semantics: give meanings to programs Domain: a world of ideas, or mathematical objects An expression is just a name for an idea in domain Compose meanings of composite expressions Diego E. Alonso Introduction to Functional Reactive Programming with Scala 8 / 29
  • 9.
    Functional Reactive Programming Whatdoes a Reactive Programming mean, functionally Input Program Output Entities in Domain can be innite or dense We can see all input throug time as entity All output of a program though run-time as one entity A Reactive Program is map of input(t) to output(t) Diego E. Alonso Introduction to Functional Reactive Programming with Scala 9 / 29
  • 10.
    Functional Reactive Programming What'sin a program in an FRP language? X(t) + Z(t) F V (t) G Declarative approach to build reactive applications An FRP program describes signals and signal functions Signals are values that may vary over time Signal functions show how signals depend on each other Diego E. Alonso Introduction to Functional Reactive Programming with Scala 10 / 29
  • 11.
    Functional Reactive Programming Interpretationof FRP program by sampling X(t) + Z(t) F V (t) G To run an FRP program we need an interpreter It builds a long stream of samples (with times) Each signal function is run as a stream transformer FRP splits time-sampling from continuous logic Sample at the edge of the program Diego E. Alonso Introduction to Functional Reactive Programming with Scala 11 / 29
  • 12.
    Arrowised Functional ReactiveProgramming Simple FRP uses combinators of signals X(t) + Z(t) F V (t) G Classic FRP works at the level of Signals: Sig[X] Transform value of signal using function Combine values of xed independent signals Use value of signal to build another signal Use value of signal to control which other signal follows These is done with operations of Monad typeclass Diego E. Alonso Introduction to Functional Reactive Programming with Scala 12 / 29
  • 13.
    Arrowised Functional ReactiveProgramming Arrowised FRP: functions instead of signals X(t) + Z(t) F V (t) G Arrowised FRP works only at level of Signal Functions (SF) In AFRP, you start from some basic SFs You combine them using Arrow operations Diego E. Alonso Introduction to Functional Reactive Programming with Scala 13 / 29
  • 14.
    Arrowised Functional ReactiveProgramming The Arrow Type Class X(t) + Z(t) F V (t) G Monad is class for types F[V ] of values V in eect F, it gives operations to make F-values from F-values Arrow is class for types A[I, O] of A-functions from I to O with operations to transform A-functions into A-functions Mix A-functions into an A-function on tuples or eithers Compose A-functions into a single one Diego E. Alonso Introduction to Functional Reactive Programming with Scala 14 / 29
  • 15.
    From Lists toMonadic Stream Functions Starting from a Scala List sealed trait List[T] case class Nil[T]() extends List[T] case class Cons(head: T, tail: List[T] The data type marks end or continuation Backed by a data structure Diego E. Alonso Introduction to Functional Reactive Programming with Scala 15 / 29
  • 16.
    From Lists toMonadic Stream Functions Scala Lists as a trait with two methods trait List[T] { def head: Option[T] def tail: Option[List[T]] } Methods need not be backed by data structure The Option marks if it is the end of list Diego E. Alonso Introduction to Functional Reactive Programming with Scala 16 / 29
  • 17.
    From Lists toMonadic Stream Functions Lists as traits with a single methods trait List[T] { def uncons: Option[(T, List[T])] } trait InfList[T] { def uncons: Id[(T, InfList[T])] } In eect, Option means may-terminate, and Id that not Diego E. Alonso Introduction to Functional Reactive Programming with Scala 17 / 29
  • 18.
    From Lists toMonadic Stream Functions Monadic Streams: generic sequence of eectful steps trait MonSt[F[_], T] { def uncons: F[(T, MonSt[F, T])] } Monadic streams are generic on the eect The eect covers both the head and the tail of the stream Instances of MonSt can include state, and pass new state in tail Diego E. Alonso Introduction to Functional Reactive Programming with Scala 18 / 29
  • 19.
    Monadic Stream Functions Denitionof the Monadic Stream Functions trait trait MoSF[F[_], In, Out] { def apply(i: In): F[(Out, This)] type This = MoSF[F, In, Out] } takes an input In, and runs computation in F that returns value Out and a continuation An instance of MoSF can have inner state the instance of continuation has next state Generalises lists, monadic streams, and sinks Diego E. Alonso Introduction to Functional Reactive Programming with Scala 19 / 29
  • 20.
    Monadic Stream Functions Basicand stateless MoSF Basic constructors: make a MoSF[F, I, O] from Value Type Function Type Eectless pure O arr I ⇒ O Eectful liftM F[O] arrM I ⇒ F[O] pure is an MoSF that always returns given value arr is an MoSF that always applies given function liftM is an MoSF that always perform given F arrM is an MoSF that applies given computation Diego E. Alonso Introduction to Functional Reactive Programming with Scala 20 / 29
  • 21.
    Monadic Stream Functions arr:return result of function case class arr[F[_]: App, I, O]( fun: I = O) extends MoSF[F, I, O] { self = def apply(i: I): F[(O, This)] = ( fun(i) - self ).pure } case class liftM[F[_]: Functor, I, O](fo: F[O]) extends MoSF[F, I, O] { self = def apply(i: I): F[(O, This)] = fo.map( o = o - self ) } // type This = MoSF[F, I, O] Diego E. Alonso Introduction to Functional Reactive Programming with Scala 21 / 29
  • 22.
    Monadic Stream Functions ap:merge input-wise two independent MoSF def ap[F[_]: App, In, Mid, Out]( sffun: MoSF[F, In, Mid = O], sfmid: MoSF[F, In, Mid] ): MoSF[F, In, Out] = (i: In) = App[F].map2(sffun(i), sfmid(i)) { case ( (fun, fkont), (arg, mkont) ) = fun(arg) - ap(fkont, mkont) } Diego E. Alonso Introduction to Functional Reactive Programming with Scala 22 / 29
  • 23.
    Monadic Stream Functions andThen:pass output to another MoSF def andThen[F[_]: Monad, In, Mid, Out]( mosf: MoSF[F, In, Mid], post: MoSF[F, Mid, Out] ): MoSF[F, In, Out] = (i: In) = for { (m, mosfK) - mosf(i) (o, postK) - post(m) } yield o - andThen(mosf, postK) Continuation is composition of continuations Diego E. Alonso Introduction to Functional Reactive Programming with Scala 23 / 29
  • 24.
    Monadic Stream Functions rst:pair inputs and output of MoSF with extra def first[F[_]: Functor, In, Out, eX]( mosf: MoSF[F, In, Out] ): MoSF[F, (In,eX), (Out,eX)] = { case (i, x) = mosf(i) map { case (o, cont) = (o, x) - cont.first }} applies mosf to the rst element pairs it with the second element Diego E. Alonso Introduction to Functional Reactive Programming with Scala 24 / 29
  • 25.
    Monadic Stream Functions left:handle case Left, pass Right through case class left[F[_]: App, I, O, X]( mosf: MoSF[F, I, O] ) extends MoSF[F, I or X, O or X] { self = def apply(iox: I or X): M[(O or X, This)] = iox match { case Right(x) = (Right(x) - self).pure case Left(i) = mosf(i).map { case (o, cont) = Left(o) - cont.left } // type This = MoSF[I or X, O or X] } // type or[A,B] = Either[A,B] Diego E. Alonso Introduction to Functional Reactive Programming with Scala 25 / 29
  • 26.
    Monadic Stream Functionsand Monadic Streams Can we make a MoSF from Monadic Stream trait MoSF[F[_], I, O] { def apply(i: I): F[(O, MoSF[F, I, O])] } trait MoSt[G[_], T] { def uncons: G[ (T, MoSt[G,T]) ] } // type MoSt[G[_], T] = MoSF[G, Unit, O] // type MoSF[F[_], I, O] = MoSt[ ******* , *] So, MoSt[G, T] is just a MoSF[G, Unit, T] Can we make a MoSF on top of a MoST? Diego E. Alonso Introduction to Functional Reactive Programming with Scala 26 / 29
  • 27.
    Monadic Stream Functionsand Monadic Streams YES, if we integrate the input into the eect of stream trait MoSF[F[_], I, O] { def apply(i: I): F[(O, MoSF[F, I, O])] } trait MoSt[G[_], T] { def uncons: G[ (T, MoSt[G,T]) ] } // type MoSt[G[_], T] = MoSF[G, Unit, O] // type MoSF[F[_], I, O] = MoSt[ Kl[F,I,?], O] // type Kl[F[_], I, O] = I = F[O] Diego E. Alonso Introduction to Functional Reactive Programming with Scala 27 / 29
  • 28.
    Summary FRP is usefulabstraction to describe reactive applications Arrows is useful type-class for composing eectful computations We can implement and use FRP in Scala Next work: follow trend to do Monadic Stream Functions on FS2 Diego E. Alonso Introduction to Functional Reactive Programming with Scala 28 / 29
  • 29.
    Thank you to:I Functional Reactive Programming, Refactored. Perez, Barenz, Nilsson. Haskell Symposium, 2016. Genuinely Functional User Interfaces. Courtney, Elliott. The Essence and Origins of Functional Reactive Programming. Elliott. LambdaJam 2015. Diego E. Alonso Introduction to Functional Reactive Programming with Scala 29 / 29