Upload
eddy-bertoluzzo
View
277
Download
1
Embed Size (px)
Citation preview
The Essence of Reactive ProgrammingA Theoretical Approach
Eddy Bertoluzzo
What does it mean to be Reactive?
● Reactive Programming - Wikipedia
Let’s ask Google
Reactive Programming - Wikipedia
● Reactive Programming - Wikipedia
● ReactiveX - Rx*
● Functional Reactive Programming
Let’s ask Google
Reactive Programming
???
Functional Reactive Programming
Reactive Programming
!=
Functional Reactive Programming
● Reactive Programming - Wikipedia
● ReactiveX - Rx*
● Functional Reactive Programming
● Reactive Manifesto - Reactive
Streams
Let’s ask Google
● Reactive Programming - Wikipedia
● ReactiveX - Rx*
● Functional Reactive Programming
● Reactive Manifesto - Reactive
Streams
Let’s ask Google
Quoting Leslie Lamport
“There’s something about the culture of software that has impeded the use
of specification.
We have a wonderful way of describing things precisely that’s
been developed over the last couple of millennia, called mathematics.
I think that’s what we should be using as a way of thinking about
what we build.”
The Four Fundamental Effects
One Many
Sync a Iterable a
Async Future a ???
The Four Fundamental Effects
One Many
Sync a Iterable a
Async Future a Reactive Programming
Can you feel the Duality tonight?
Interactive vs Reactive
Sync vs Async
Pull vs Push
Iterable vs ???
Iterable
data Iterator a = Iterator
{ moveNext :: () -> IO Bool
, current :: () -> a
}
newtype Iterable a = Iterable
{ getIterator :: () -> IO (Iterator a)
}
Optional Values
data Maybe a = Nothing | Just a
Iterable
data Iterator a = Iterator
{ moveNext :: () -> IO Bool
, current :: () -> a
}
newtype Iterable a = Iterable
{ getIterator :: () -> IO (Iterator a)
}
Iterable
data Iterator a = Iterator
{ moveNext :: () -> IO (Maybe a)
}
newtype Iterable a = Iterable
{ getIterator :: () -> IO (Iterator a)
}
Coproducts
data Either a b = Left a | Right b
Iterable
data Iterator a = Iterator
{ moveNext :: () -> IO (Maybe a)
}
newtype Iterable a = Iterable
{ getIterator :: () -> IO (Iterator a)
}
Iterable
data Iterator a = Iterator
{ moveNext :: () -> IO (Either SomeException (Maybe a))
}
newtype Iterable a = Iterable
{ getIterator :: () -> IO (Iterator a)
}
Iterable
type Iterator a = () -> IO (Either SomeException (Maybe a))
type Iterable a = () -> IO (Iterator a)
Iterable
type Iterator a = () -> IO a
type Iterable a = () -> IO (Iterator a)
Iterable
type Iterator a = () -> IO a
type Iterable a = () -> IO (() -> IO a)
Iterator == Getter
() -> IO a
Covariance
a <: b
Iterator a <: Iterator b
Covariance
a <: b
Iterator a <: Iterator b
Covariance
Coke <: Drink
VCoke
<: VDrink
Functor
fmap :: (a -> b)
-> Iterator a
-> Iterator b
fmap f ia = \() -> f (ia ())
fmap f ia = f . ia -- g (f (x)) = g . f
fmap = (.)
Iterable == Getter of Getters
() -> IO (() -> IO a)
Iterable == Getter of Getters
() -> IO (() -> IO a)
Lifting
Transform a function into a corresponding function within another - usually more general - setting.
lift :: (Iterator a -> Iterator b)
-> Iterable a
-> Iterable b
lift f iia = \() -> f (iia ())
lift = (.)
Functor
fmap' :: (a -> b)
-> Iterable a
-> Iterable b
fmap' f iia = lift (fmap f) iia
Applying Duality
==
Reverse all the ->
Observer
type Iterator a = () -> IO a
= () IO <- a
type Observer a = a -> IO ()
Observer
type Iterator a = () -> IO a
= () IO <- a
type Observer a = a -> IO ()
Observer
type Iterator a = () -> IO a
= () IO <- a
type Observer a = a -> IO ()
Observable
type Iterable a = () -> IO (() -> IO a)
= () IO <- (() IO <- a)
type Observable a = (a -> IO ()) -> IO ()
Observable
type Iterable a = () -> IO (() -> IO a)
= () IO <- (() IO <- a)
type Observable a = (a -> IO ()) -> IO ()
Observable
type Iterable a = () -> IO (() -> IO a)
= () IO <- (() IO <- a)
type Observable a = (a -> IO ()) -> IO ()
Observable
type Observer a = a -> IO ()
type Observable a = (a -> IO ()) -> IO ()
Observer == Setter
a -> IO ()
Contravariance
a <: b
Observer b <: Observer a
Contravariance
a <: b
Observer b <: Observer a
Contravariance
Coke <: Drink
RDrink
<: RCoke
Contravariant Functor
contramap :: (a -> b)
-> Observer b
-> Observer a
contramap f ob = \a -> ob (f a)
contramap f ob = ob . f
contramap = flip (.)
Observable == Setter of Setters
(a -> IO ()) -> IO ()
Observable == Setter of Setters
(a -> IO ()) -> IO ()
Lifting
lift :: (Observer b -> Observer a)
-> Observable a
-> Observable b
lift f ooa = \ob -> ooa (f ob)
lift f ooa = ooa . f
lift = flip (.)
Functor
fmap :: (a -> b)
-> Observable a
-> Observable b
fmap f ooa = lift (contramap f) ooa
Continuation Passing Style (CPS)Suspended computation taking a continuation as argument. Instead of returning a result, they will push it to the continuation.
cps :: (a -> r) -> r
add :: Int -> Int -> Int
add x y = x + y
add_cps :: Int -> Int -> ((Int -> r) -> r)
add_cps x y = \k -> k (x + y)
Observable == CPS function
cps :: (a -> r ) -> r
observable :: (a -> IO ()) -> IO ()
Observable
type Observer a = a -> IO ()
type Observable a = (a -> IO ()) -> IO ()
Observable
type Observer a =
Either SomeException (Maybe a) -> IO ()
type Observable a = (Observer a) -> IO ()
Observable
newtype Observer a = Observer
{ onNext :: Either SomeException (Maybe a) -> IO ()
}
newtype Observable a =
{ subscribe :: (Observer a) -> IO ()
}
Observable
data Observer a = Observer
{ onNext :: a -> IO ()
, onError :: SomeException -> IO ()
, onCompleted :: IO ()
}
newtype Observable a =
{ subscribe :: (Observer a) -> IO ()
}
The Four Fundamental Effects
One Many
Sync a Iterable a
Async Future a Observable a
What about backpressure?
Quoting Gérard Berry
Interactive programs interact at their own speed with users or with other programs…
Reactive programs also maintain a continuous interaction with their environment, but at a speed which is determined by the environment, not by the program itself.
Producer Consumer
Reactive
Interactive
Reactive Streamspublic interface Publisher<T> {
public void subscribe(Subscriber<? super T> s);
}
public interface Subscriber<T> {
public void onSubscribe(Subscription s);
public void onNext(T t);
public void onError(Throwable t);
public void onComplete();
}
Reactive Streams
public interface Subscription {
public void request(long n);
public void cancel();
}
AsyncIterable
data AsyncIterator a = AsyncIterator
{ moveNext :: () -> IO (Future Bool)
, current :: () -> a
}
newtype AsyncIterable a = AsyncIterable
{ getAsyncIterable :: () -> AsyncIterable a
}
The Four Fundamental Effects
One Many
Sync a Iterable a
Async Future a Observable a
AsyncIterable a
Use the Right Tool for the Right Job
Thank you
Eddy [email protected]