際際滷

際際滷Share a Scribd company logo
Awesomely descriptive JavaScript
with Monads
Theory
Monad laws
return a >>= f  f a
m >>= return  m
(m >>= f) >>= g  m >>= (x -> f x >>= g)
Monad laws
Practical theory
Awesomely descriptive JavaScript with monads
V E G E T A B L E
A
L
U
E
Awesomely descriptive JavaScript with monads
Awesomely descriptive JavaScript with monads
P => M<S>
f
=>
unit
P => M<P>
( , ) =>
bind
( M<P> , P => M<S> ) => M<S>
( M<P> , P => M<S> ) => M<S>M<P> P => M<S> M<S>
extract
value
bind
function
m(x)
x
x => m(y) m(y)
bind
Monad laws (JavaScript)
bind( unit(v) , f )  f(v)
bind( monad , unit )  monad
bind( bind( monad , f ) , g ) 
bind( monad, v => bind( f(v) , g ) )
monet.js
UNIT
Identity(x)
Maybe.Some(x)
Maybe.None()
Either.Left(e)
Either.Right(x)
List(x, Nil)
monad.bind(f)
monad.flatMap(f)
monad.chain(f)
BIND
Monad laws (monet.js / Identity)
Identity(v).flatMap(f)  f(v)
id.flatMap(Identity)  id
id.flatMap(f).flatMap( g ) 
id.flatMap(v => f(v).flatMap(g))
Practice: Identity
UNIT
Identity(x)
Maybe.Some(x)
Maybe.None()
Either.Left(e)
Either.Right(x)
List(x, Nil)
monad.bind(f)
monad.flatMap(f)
monad.chain(f)
BIND
var pepperInABowl = getBowlOf('pepper', 'red');
var pepper = pepperInABowl.get();
var slicedPepperInABowl = slice(pepper);
var tomatoInABowl = getBowlOf('tomato');
var tomato = tomatoInABowl.get();
var slicedTomatoInABowl = slice(tomato);
var slicedPepper = slicedPepperInABowl.get();
var slicedTomato = slicedTomatoInABowl.get();
var mixInABowl = mix(slicedPepper, slicedTomato);
Awesomely descriptive JavaScript with monads
const mixInABowl = getBowlOf('pepper')
.flatMap(slice)
.faltMap(silcedPepper => getBowlOf('tomato')
.flatMap(slice)
.faltMap(mixedTomato =>
mix(silcedPepper , mixedTomato)));
Awesomely descriptive JavaScript with monads
But HOW ?
interface Bowl<V> {
get(): V;
}
getBowlOf<V>(name: string): Bowl<V>;
slice<S>(vegetable: Vege): Bowl<S>;
mix<M>(...ingredients): Bowl<M>;
var pepperInABowl = getBowlOf('pepper');
var pepper = pepperInABowl.get();
var slicedPepperInABowl = slice(pepper);
var tomatoInABowl = getBowlOf('tomato');
var tomato = tomatoInABowl.get();
var slicedTomatoInABowl = slice(tomato);
var slicedPepper = slicedPepperInABowl.get();
var slicedTomato = slicedTomatoInABowl.get();
var mixInABowl = mix(slicedPepper, slicedTomato);
var pepperInABowl = getBowlOf('pepper');
var pepper = pepperInABowl.get();
var slicedPepperInABowl = slice(pepper);
var tomatoInABowl = getBowlOf('tomato');
var tomato = tomatoInABowl.get();
var slicedTomatoInABowl = slice(tomato);
var slicedPepper = slicedPepperInABowl.get();
var slicedTomato = slicedTomatoInABowl.get();
var mixInABowl = mix(slicedPepper, slicedTomato);
var pepperInABowl = getBowlOf('pepper');
var pepper = pepperInABowl.get();
var slicedPepperInABowl = slice(pepper);
var tomatoInABowl = getBowlOf('tomato');
var tomato = tomatoInABowl.get();
var slicedTomatoInABowl = slice(tomato);
var slicedPepper = slicedPepperInABowl.get();
var slicedTomato = slicedTomatoInABowl.get();
var mixInABowl = mix(slicedPepper, slicedTomato);
var pepperInABowl = getBowlOf('pepper');
var pepper = pepperInABowl.get();
var slicedPepperInABowl = slice(pepper);
var tomatoInABowl = getBowlOf('tomato');
var tomato = tomatoInABowl.get();
var slicedTomatoInABowl = slice(tomato);
var slicedPepper = slicedPepperInABowl.get();
var slicedTomato = slicedTomatoInABowl.get();
var mixInABowl = mix(slicedPepper, slicedTomato);
monet.js
Identity(  )
type Op<A, B> = (val:A) => Bowl<B>;
interface Bowl<V> {
get(): V;
flatMap<S>(f: Op<V, S>): Bowl<S>;
}
goo.gl/dh9DrZ
var pepperInABowl = getBowlOf('pepper');
var pepper = pepperInABowl.get();
var slicedPepperInABowl = slice(pepper);
var tomatoInABowl = getBowlOf('tomato');
var tomato = tomatoInABowl.get();
var slicedTomatoInABowl = slice(tomato);
var slicedPepper = slicedPepperInABowl.get();
var slicedTomato = slicedTomatoInABowl.get();
var mixInABowl = mix(slicedPepper, slicedTomato);
const slicedPepperInABowl =
getBowlOf('pepper').flatMap(slice);
var pepperInABowl = getBowlOf('pepper');
var pepper = pepperInABowl.get();
var slicedPepperInABowl = slice(pepper);
var tomatoInABowl = getBowlOf('tomato');
var tomato = tomatoInABowl.get();
var slicedTomatoInABowl = slice(tomato);
var slicedPepper = slicedPepperInABowl.get();
var slicedTomato = slicedTomatoInABowl.get();
var mixInABowl = mix(slicedPepper, slicedTomato);
const slicedPepperInABowl =
getBowlOf('pepper').flatMap(slice);
const slicedTomatoInABowl =
getBowlOf('tomato').flatMap(slice);
var pepperInABowl = getBowlOf('pepper');
var pepper = pepperInABowl.get();
var slicedPepperInABowl = slice(pepper);
var tomatoInABowl = getBowlOf('tomato');
var tomato = tomatoInABowl.get();
var slicedTomatoInABowl = slice(tomato);
var slicedPepper = slicedPepperInABowl.get();
var slicedTomato = slicedTomatoInABowl.get();
var mixInABowl = mix(slicedPepper, slicedTomato);
const slicedPepperInABowl =
getBowlOf('pepper').flatMap(slice);
const mixInABowl = getBowlOf('pepper')
.flatMap(slice)
.faltMap(silcedPepper =>
mix(silcedPepper , slicedPepperInABowl.get()));
const slicedPepperInABowl =
getBowlOf('pepper').flatMap(slice);
const mixInABowl = getBowlOf('pepper')
.flatMap(slice)
.flatMap(silcedPepper => slicedPepperInABowl
.flatMap(mixedTomato =>
mix(silcedPepper , mixedTomato)));
const mixInABowl = getBowlOf('pepper')
.flatMap(slice)
.faltMap(silcedPepper => getBowlOf('tomato')
.flatMap(slice)
.flatMap(mixedTomato =>
mix(silcedPepper , mixedTomato)));
var pepperInABowl = getBowlOf('pepper', 'red');
var pepper = pepperInABowl.get();
var slicedPepperInABowl = slice(pepper);
var tomatoInABowl = getBowlOf('tomato');
var tomato = tomatoInABowl.get();
var slicedTomatoInABowl = slice(tomato);
var slicedPepper = slicedPepperInABowl.get();
var slicedTomato = slicedTomatoInABowl.get();
var mixInABowl = mix(slicedPepper, slicedTomato);
Practice: Maybe
UNIT
Identity(x)
Maybe.Some(x)
Maybe.None()
Either.Left(e)
Either.Right(x)
List(x, Nil)
monad.bind(f)
monad.flatMap(f)
monad.chain(f)
BIND
Awesomely descriptive JavaScript with monads
let spiceMix;
const salt = getSpice('salt');
let coriander = getSpice('coriander');
if (coriander) {
coriander = crush(coriander);
}
if (coriander && salt && isPowdered(salt)) {
spiceMix = mixSpice(salt , coriander);
}
spiceMix = vegeta;
let spiceMix;
const salt = getSpice('salt');
let coriander = getSpice('coriander');
if (coriander) {
coriander = crush(coriander);
}
if (coriander && salt && isPowdered(salt)) {
spiceMix = mixSpice(salt , coriander);
}
spiceMix = vegeta;
const spiceMix = getSpice('salt').filter(isPowdered)
.flatMap(salt =>
getSpice('coriander').map(crush)
.flatMap(coriander =>
mixSpice(salt , coriadner)))
.orJust(vegeta);
But HOW ?
getSpice<V>(name: string): Maybe<V>;
crush(spice: S): S;
isPowdered(spice: S): boolean;
Awesomely descriptive JavaScript with monads
getSpice<V>(name: string): Maybe<V>;
crush(spice: S): S;
isPowdered(spice: S): boolean;
Awesomely descriptive JavaScript with monads
getSpice<V>(name: string): Maybe<V>;
crush(spice: S): S;
isPowdered(spice: S): boolean;
monet.js
Maybe
interface Maybe<T> {
flatMap<V>(fn: (val: T) => Maybe<V>): Maybe<V>;
map<V>(fn: (val: T) => V): Maybe<V>;
filter(fn: (val: T) => boolean): Maybe<T>;
orJust(val: T): T;
}
const silkySalt = getSpice('salt').filter(isPowdered);
const crushedCoriander = getSpice('coriander').map(crush);
const spiceMixMaybe = silkySalt.flatMap(salt =>
crushedCoriander.flatMap(coriander =>
mixSpice( salt , coriadner )));
const spiceMix = spiceMixMaybe.orJust(vegeta);
const crushedCoriander = getSpice('coriander').map(crush);
const spiceMixMaybe =
getSpice('salt').filter(isPowdered).flatMap(salt =>
crushedCoriander.flatMap(coriander =>
mixSpice( salt , coriadner )));
const spiceMix = spiceMixMaybe.orJust(vegeta);
const spiceMixMaybe =
getSpice('salt').filter(isPowdered).flatMap(salt =>
getSpice('coriander').map(crush).flatMap(coriander =>
mixSpice( salt , coriadner )));
const spiceMix = spiceMixMaybe.orJust(vegeta);
const spiceMixMaybe = getSpice('salt').filter(isPowdered)
.flatMap(salt =>
getSpice('coriander').map(crush)
.flatMap(coriander =>
mixSpice( salt , coriadner )));
const spiceMix = spiceMixMaybe.orJust(vegeta);
const spiceMix = getSpice('salt').filter(isPowdered)
.flatMap(salt =>
getSpice('coriander').map(crush)
.flatMap(coriander =>
mixSpice( salt , coriadner )));
.orJust(vegeta)
const spiceMix = getSpice('salt')
.filter(isPowdered)
.flatMap(salt =>
getSpice('coriander')
.map(crush)
.flatMap(coriander =>
mixSpice(salt , coriadner)))
.orJust(vegeta);
null
getSpice<V>(name: string): Maybe<V> {
let spice = locker.get(name);
if (spice != null) {
return Some(spice);
}
return None();
}
getSpice<V>(name: string): Maybe<V> {
const spice = locker.get(name);
if (spice != null) {
return Some(spice);
}
return None();
}
getSpice<V>(name: string): Maybe<V> {
const spice = locker.get(name);
if (spice != null) {
return  ?
}
return None();
}
monet.js
Some(  )
getSpice<V>(name: string): Maybe<V> {
const spice = locker.get(name);
if (spice != null) {
return Some(spice);
}
return None();
}
monet.js
None()
getSpice<V>(name: string): Maybe<V> {
const spice = locker.get(name);
if (spice != null) {
return Some(spice);
}
return None();
}
monet.js
.fromNull()
getSpice<V>(name: string): Maybe<V> {
return Maybe.fromNull(
locker.get(name)
);
}
Awesomely descriptive JavaScript with monads
goo.gl/cvGVeo
const saladBowl = mixInABowl
.flatMap(mixedVegetables =>
mix(mixedVegetables, spiceMix));
e a t i t
Monads
Identity
Maybe
Either
Validation
List
NEL
Reader
Free
IO
?
Monads
Identity
Maybe
Either
Validation
List
NEL
Reader
Free
IO
Promise
T H X
Jakub . Strojewski @gmail.com
u l f r y k

More Related Content

Awesomely descriptive JavaScript with monads

Editor's Notes

  • #10: Story about doing things in kitchen.
  • #27: var pepperInABowl = getBowlOf('pepper', 'red'); var pepper = pepperInABowl.get(); var slicedPepperInABowl = slice(pepper);
  • #28: var tomatoInABowl = getBowlOf('tomato'); var tomato = tomatoInABowl.get(); var slicedTomatoInABowl = slice(tomato);
  • #29: var slicedPepper = slicedPepperInABowl.get(); var slicedTomato = slicedTomatoInABowl.get();
  • #30: var mixInABowl = mix(slicedPepper, slicedTomato);
  • #31: Part of implementation
  • #32: interface Bowl<V> { get(): V; }
  • #33: You can play around :)
  • #34: var pepperInABowl = getBowlOf('pepper', 'red'); var pepper = pepperInABowl.get(); var slicedPepperInABowl = slice(pepper);
  • #36: var tomatoInABowl = getBowlOf('tomato'); var tomato = tomatoInABowl.get(); var slicedTomatoInABowl = slice(tomato);
  • #38: var slicedPepper = slicedPepperInABowl.get(); var slicedTomato = slicedTomatoInABowl.get(); var mixInABowl = mix(slicedPepper, slicedTomato);
  • #46: statefull imperative
  • #73: simple accurate
  • #74: Article intro to monads