JSDC 2014 - functional java script, why or why not

283
Functional JavaScript, Why or Why Not? JSDC 2014 bit.ly/jsdc2014-funjs

Transcript of JSDC 2014 - functional java script, why or why not

Functional JavaScript, Why or Why Not?

JSDC 2014

bit.ly/jsdc2014-funjs

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Motivation

Outline

This talk is about

ConceptsFeaturesTrade-OffLibrariesFrameworks

This talk is NOT about

20 mins to write a blog (you had enough of it, right?)

42 Tools for your toolbox (although I do recommend to use some libraries)

Hammer on your hand and everything looks like a nail

Brainwash believe whatever you want; so, hacking, not blaming Lambda Calculus ...wait, or should we put it in slides?

Premise

No Compiler(No magic!)

Concepts

Functional Programming?

Which one is better?

Which one is better?more useful?

OOP FP

Functional Programming is about

PurityContextEvaluationCompositionTransformation

It would bring you

Re-thinking about programming

Patterns efficiently make your works done

Fun -citons

Features of Functional Programmings

First-class function | Closure

High-order functions | Function composition

Purity | Managed side-effects | Laziness

Recursion | Tail-recursion optimization | (Type)

Features of Functional Programmings

First-class function | Closure

High-order functions | Function composition

Purity | Managed side-effects | Laziness

Recursion | Tail-recursion optimization | (Type)

JavaScript Ready

Need some hard works

Impossible if runtime doesn't support it (well)

Discuss it later...

function() {} is everything

function() {} is everything

Or () => { } if you're a lucky bastard

Use Firefox to embrace () => 'the power of ES6!'(Fat Arrow Functions)

65535 -- Number (*yes, it's a function)

65535 + 1 -- Number → Number → Number

[1] -- Array Number

[1].push(2) -- Array Number → Number → Array Number

[1, 2, 3].length -- Array Number → Number

[1, 2, 3].map((x) => `${ x }`) -- Array Number → (Number → String) → Array String

Use FirefoxNightly to embrace `the ${power} of ES6!`(Quasi-Literals)

About the signature

Array Number → (Number → String) → Array String

[a] → (a → b) → [b]

"return value"function as argumentargument

a, b: type variables

var arr = [1, 2, 3]arr.push(4)

But what about...

var arr = [1, 2, 3]arr.push(4)

But what about...

=== return a completely new Array: arr → arr'=== Array Number → Number → Array Number

Immutable Data Structure

Immutable Data StructureBut in JavaScript we can 'pretend' we have it when we're playing with FP. Would discuss it later

Immutable Data StructureBut in JavaScript we can 'pretend' we have it when we're playing with FP. Would discuss it later

Facebook has an 'immutable-js' libraryhttps://github.com/facebook/immutable-js

So now we have the Transformation

65535 -- Number (*yes, it's a function)

65535 + 1 -- Number → Number

[1] -- Array Number

[1].push(2) -- Array Number → Number → Array Number

[1, 2, 3].length -- Array Number → Number

[1, 2, 3].map((x) => `${ x }`) -- Array Number → (Number → String) → Array String

So now we have the Transformation

So now we have the Transformation

ba

But we need to Composethem together

Part One.High-Order Functions

[1,2,3].map((x) => `${ x }`)

[1,2,3].map((x) => `${ x }`)Array Number → (Number → String) → Array String

Receive functions as arguments

High-Order Functions is useful

map:: [a] → (a → b) → [b]

reduce:: [a] → (a → b → b) → [a] → b

High-Order Functions is useful

map:: [a] → (a → b) → [b]

reduce:: [a] → (a → b → b) → [a] → b

-- Note: these are *NOT* correct signatures in Haskell

-- but in JavaScript, we can treat [1,2,3].map as map::[a]...

-- which makes the code matches the type better

No more looping & ijk tricks

var result = [];for (var i = 0; i < selectors.length; i++) { var selector = selectors[i]; result.push(document.querySelector(selector));}

var result = selectors.map( (selector) => document.querySelector(selector));

It's not only about SLOC

for (var r = 0; r < records.length; r += 1) { var record = records[r]; var typeStr = NfcUtils.toUTF8(record.type); if (NfcUtils.equalArrays(record.type, NDEF.RTD_TEXT)) { poster.text = poster.text || {}; var textData = NDEF.payload.decodeText(record.payload); if (poster.text[textData.language]) { // According to NFCForum-SmartPoster_RTD_1.0 3.3.2, // there MUST NOT be two or more records with // the same language identifier. return null;

// to be continue...

reduce:: [a] → b

reduce:: [a] → b~= build things in this case

return records.reduce((poster, record) => { var typeStr = NfcUtils.toUTF8(record.type); if (NfcUtils.equalArrays(record.type, NDEF.RTD_TEXT)) { poster.text = poster.text || {}; var textData = NDEF.payload.decodeText(record.payload); if (poster.text[textData.language]) { // According to NFCForum-SmartPoster_RTD_1.0 3.3.2, // there MUST NOT be two or more records with // the same language identifier. return null;

// to be continue...

return records.reduce((poster, record) => { var typeStr = NfcUtils.toUTF8(record.type); if (NfcUtils.equalArrays(record.type, NDEF.RTD_TEXT)) { poster.text = poster.text || {}; var textData = NDEF.payload.decodeText(record.payload); if (poster.text[textData.language]) { // According to NFCForum-SmartPoster_RTD_1.0 3.3.2, // there MUST NOT be two or more records with // the same language identifier. return null;

// to be continue...

A real case in Gaia project: Bug 1039245

People know what are you doing when they saw the 'map' and 'reduce'

People know what are you doing when they saw the 'map' and 'reduce'

If there is no or only few side-effects

It can be more powerful if you play with the type

map:: [a] → (a → b) → [b]

map:: [a] → (a → b) → [b]

while a/URL, b/IO

urls.map((url) => Http.get(url) .filter((response) => response.status !== 404 ) .map((response) => Parser.comment(response)) .map((comment) => UI.renderComment(comment)) .execute()

urls.map((url) => Http.get(url) // map (URL -> IO) to [ URL ] .filter((response) => response.status !== 404 ) .map((response) => Parser.comment(response)) .map((comment) => UI.renderComment(comment)) .execute()

// If we have lazy IO & async mixed Monad // Transformer...will discuss it later

urls.map((url) => Http.get(url) // map (URL -> IO) to [ URL ] .filter((response) => response.status !== 404 ) .map((response) => Parser.comment(response)) .map((comment) => UI.renderComment(comment)) .execute()

// If we have lazy IO & async mixed Monad // Transformer...will discuss it later

[URL] → [IO a] → [Parsed b] → [DOM c]

Not only handle data

Some advanced High-OrderFunctions of list

forEach:: [a] → (a → SideEffect; will discuss it later)

filter:: [a] → (a → Bool) → [a] * the type is similar with map

groupBy:: [a] → (a → a → Bool) → [[a]] * lo-dash has it

zipWith: [a] →[b] → (a → b → c) → [c] * worth to implement

forEach:: [a] → (a → SideEffect; will discuss it later)

filter:: [a] → (a → Bool) → [a] * the type is similar with map

groupBy:: [a] → (a → a → Bool) → [[a]] * lo-dash has it

zipWith: [a] →[b] → (a → b → c) → [c] * worth to implement

Recommends to use lo-dash library to acquire these functions

And reducing is even more basic

var map = (xs, fn) => { return xs.reduce((acc, x) => { return acc.concat([ fn(x) ]); }, []); };

Recommends to use and get understand the 'transducer.js'

Summary: High-Order Functions is useful, especially for list

Do map & reduce wheneverit's possible

With type in mind we can do lots of things, not only handling data

With type in mind we can do lots of things, not only handling data

We'll see more cases soon

And the best thing is major browsers support map & reduce already

Part Two.Function Composition

In Functional Programming we don't like to define new function

Instead, we compose themwhen we need it

map (not.odd) [1,2,3]

map (not.odd) [1,2,3]

(.):: (b → c) → (a → b) → (a → c)

Is much better than

map (\x -> !odd x) [1,2,3]

let notOdd x = not(odd x);

map notOdd [1,2,3]

This is important because

Safety if small functions are safe, the larger one is safe, too

Reusability no need to create new functions

Flexibility compose anything you want at anytime

Composition is good for you

Unfortunately in JavaScript we don't have such nice syntax support

map (not.odd.read) ["1","2","3"]

[1,2,3].map(compose(not, odd, read))

Recommends to use lo-dash library to acquire the compose functions

map (not.odd.read) ["1","2","3"]

[1,2,3].map(compose(not, odd, read))

...?

Function composition is actually the most important idea we need to know

However in daily works we may fail to use it unless we sugar the syntax...

with the only one 'operator' we have

$(a, b, c)Although it's almost abused?

Part Three.Context & Functor

['1','2','3'].map( $(not, odd, read) )

[a] → (a → b) → [b]

[a] → (a → b) → [b]

['1','2','3'].map( $(not, odd, read) )

m a → (a → b) → m b

['1','2','3'].map( $(not, odd, read) )

m a → (a → b) → m bIO a → (a → b) → IO b

getString.map( $(not, odd, read) )IO String

m a → (a → b) → m bIO a → (a → b) → IO b[] a → (a → b) → [] b

['1','2','3'].map( $(not, odd, read) )[ ] Number

m a → (a → b) → m bIO a → (a → b) → IO b[] a → (a → b) → [] b

HTTP a → (a → b) → HTTP b

HTTPServer.map( $(not, odd, read) )HTTP Request

m a → (a → b) → m bIO a → (a → b) → IO b[] a → (a → b) → [] b

HTTP a → (a → b) → HTTP bMaybe a → (a → b) → Maybe b

maybeRead.map( $(not, odd, read) )Maybe a

m a → (a → b) → m bIO a → (a → b) → IO b[] a → (a → b) → [] b

HTTP a → (a → b) → HTTP bMaybe a → (a → b) → Maybe b

Now we have a same map & functionfor the different contexts

m a → (a → b) → m bIO a → (a → b) → IO b[] a → (a → b) → [] b

HTTP a → (a → b) → HTTP bMaybe a → (a → b) → Maybe b

Now we have a same map & functionfor the different contexts

In fact this general map called 'fmap'

List apply the function to every element ([1,2,3])

HTTP receive request and response with the handled content

Maybe if previous one is Nothing, do not apply the function

Same fmap; different meaning

The fmap is a common interface that all contexts are agreed with

Type classes with fmap calledFunctor

Functor can lift a functiononto the context

m

a

m

b( a → b)

fmap

The function keep knowing nothing about the Context

m

a

m

b( a → b)

$(not, odd, read)

fmap

It only need to care how to transform the value from a to b

How to apply context-relevant rules is encapsulated by fmap

$(not, odd, read)

List

a

List

b( a → b)

List#fmapapply the function on every element of the list

fmap

$(not, odd, read)

HTTP

a

HTTP

b( a → b)

HTTP#fmapreceive the request 'a' and response 'b' to client

fmap

$(not, odd, read)

Maybe

a

Maybe

b( a → b)

fmap

Maybe#fmapIf there is no 'a' (Nothing), do nothing

This is powerful because we can keep functions simple

And apply them into different context to do different things

HTTP

Request

HTTP

Response( Request →Response)

Needn't know how to do IO,networking, etc.

List

Request

List

Response( Request → Response)

Needn't know how to apply on every element (iterate) within the list

Contexts could even be stockpiled to do complex computations

Contexts could even be stockpiled to do complex computations

Although stockpiling is beyond Functor. See Appendix: Monad Transformer

HTTP

Request

HTTP

Response

List List

( Request →Response)Needn't know how to do IO,

networking, etc.Needn't know how to map

it to all requests.

And the stockpiling orderis very important

HTTP

Request

HTTP

Response

List List

( Request →Response)Needn't know how to do IO,

networking, etc.Needn't know how to map

it to all requests.

[HTTP Request] (buffering?)

HTTP [Request] (SPDY?)

List

Request

List

Response

HTTP HTTP

( Request →Response)Needn't know how to do IO,

networking, etc.Needn't know how to map

it to all requests.

So, Functor is an useful concept to separate context and pure function

But we still need more powerful structure to do the computation

Part Four.Monad

"When you gaze long into a Monad the Monad also gazes into you"

Monad, monad, everywhere, nor any drop to understand

Monad is a solution forcomposing Context-ed actions

In Functor we can only transform pure data to pure data

HTTP

Request

HTTP

Response( Request →Response)

( a → b )

We may have different sub-contexts for HTTP

HTTP::200HTTP::301HTTP::403HTTP::500

We can't instance different sub-contexts with only Functor

HTTP

Request

HTTP::200

Response( Request →Response)

( a → b )

HTTP

Request

HTTP::200

Response( Request →Response)

( a → b )

The 'fmap' only allow (a → b), not (a → m b)So we can't control which sub-context should be instanced

HTTP

Request

HTTP::404

Response( Request →Response)

( a → b )

The 'fmap' only allow (a → b), not (a → m b)So we can't control which sub-context should be instanced

Monad allows you to do that withits 'bind' function

(>>=):: m a → ( a → m b ) → m b

(>>=):: m a → ( a → m b ) → m b

a → m b m a

>>=m a → a a → b; b → m bunwrap wrap

Allow inject ( a → m b ) means allow we control the way to wrap the value

HTTPServer>>= (\req -> login)>>= (\authReq -> case (doAuth authReq) of

True -> content False -> authError))

HTTPServer>>= (\req -> login)>>= (\authReq -> case (doAuth authReq) of

True -> content False -> authError))

the 'bind' function, infix

HTTP::403

HTTP::200

let content response = HTTP200 responselet authError response = HTTP403 response(\authReq -> case (doAuth authReq) of

True -> content False -> authError)

( a → m b )

How 'bind' works?

(\req -> login) (\authReq -> doAuth...)>>= (......)>>=

Client ClientHTTP Monad

HTTPServer>>= (\req -> login)>>= (\authReq -> case (doAuth authReq) of

True -> content False -> authError))

The bound function stil don't need know how to open IO, networking, etc.

(a → m b)

We still keep the same interface, different implementations feature

(\req -> login) (\authReq -> doAuth...)>>= (......)>>=

Client ClientHTTP Monad

(\req -> login) (\authReq -> doAuth...)>>= (......)>>=

Map to all elements

Map to all elements

List Monad

And the Monadic actions can be chained as function composition

a → m c

a -> m b b -> m c>>=

a → m c

a -> m b b -> m c>>=

actionFoo = actionA >>= actionBactionBar = actionFoo >>= actionC

(and so on...)

It's just like Function CompositionBut now we can handle Contexts

h = g 。f

h = f >>= g a → m c = a → m b >>= b → m c

a → c = b → c 。 a → b

And Monad could save us from unexpected side-effects

And Monad could save us from unexpected side-effects

if all methods with side-effectsare wrapped

getStringforkIO

openFile readTVar

+, -, *...compress

tailpar

writeArray

a → m bwhile m /IO, HTTP, UI, ...

a → b

getStringforkIO

openFile readTVar

+, -, *...compress

tailpar

writeArray

a → m bwhile m /IO, HTTP, UI, ...

a → b

Embed them rationallywith the 'bind' function

So we can combine these functions and Contexts rationally

from Gaia/System/notifications.js (v2.0)

line: 290 ~ 490 (200 lines)

from Gaia/System/notifications.js (v2.0)

line: 290 ~ 490 (200 lines)

- Create notification

- Detecting gesture

- Append notification

- Play sound

- Color one container

- Scroll container to top

...

from Gaia/System/notifications.js (v2.0)

line: 290 ~ 490 (200 lines)

There are so many

requests

from so many different

contexts

from Gaia/System/notifications.js (v2.0)

line: 290 ~ 490 (200 lines)

It's possible to use FP ideas,

to response these requests

with individual logic units is

trivial & reasonable

DOM

Create notification

Change container's style

UI

Append notification

Scroll container to top

Gesture

Detect gesture on notification

Sound

Play sound

Asynchronous

Manage asynchronous operations

Conditional Statements

If...else to do or not to do things

I/O

Get/write data and control device

...

Functor

Monad

Monad Transformer

High-order Function

Partial Application

Curry

...

This is important because no one like surprises

Another reason that Monad could encapsulate side-effects...

Xa → m b → m m c → m d → e

Xa → m b → m m c → m d → e

There is no way allowa Context-ed value to escape

There is no way allowa Context-ed value to escape

Yes, I know Comonad and unsafe- can do that, but...

So once your value get tainted, you can't use it outside the Monad

Instead, you embed your function into the tainted context

HTTPServer>>= (\req -> login)>>= (\authReq -> case (doAuth authReq) of

True -> content False -> authError))

Can only access the value when you're in the context

HTTPServer>>= (\req -> login)>>= (\authReq -> case (doAuth authReq) of

True -> content False -> authError))

let HTTPValue =

doSomething HTTPValue ...No way to do that!

extract

The similar case in JavaScript is the Promised actions

Promise(() => {...}) .then((a) => {...}) .then((b) => {...}) .then((c) => {...}) .then((d) => {...}).extract();

var promisedValue =

No way to do that!doSomething(promisedValue); ...

In fact what we could learn from Monad is not only the type & rules

But the idea to control different computations in different Contexts

Promise(() => {...}) .then((a) => {...}) .then((b) => {...}) .then((c) => {...}) .then((d) => {...});

Context: Ensure the following step executes only after the previous one get done.

$('some-selector') .each(...) .animate(...) .append(...)

Context: Select, manipulate and check the DOM element(s)

_.chain(someValue) .filter(...) .groupBy(...) .map(...) .reduce(...)

Context: Guarantee the value would be transformed by lo-dash functions

ensure() .frame() .element(...) .actions() .pulls(0, 400) .perform() .must(...)

Context: Ensure the integration test only do what user can do, instead of magic manipulations

These computations focus on the transforming within the contexts

Just like what Monadsdo in Haskell

Promise(() => {...}) .then((a) => {...}) .then((b) => {...}) .then((c) => {...}) .then((d) => {...});

$('some-selector') .each(...) .animate(...) .append(...)

_.chain(someValue) .filter(...) .groupBy(...) .map(...) .reduce(...)

DOM _Async

threeCoins = do a <- randomSt b <- randomSt c <- randomSt return (a,b,c)

main = do a <- ask "Name?" b <- ask "Age?" return ()

IO

add mx my = do x <- mx y <- my return (x + y)

MaybeState

threeCoins = do a <- randomSt b <- randomSt c <- randomSt return (a,b,c)

main = do a <- ask "Name?" b <- ask "Age?" return ()

IO

add mx my = do x <- mx y <- my return (x + y)

MaybeState

the 'do' notification

So the question is not "why we need Monad in JavaScript"

But "is it worth to implement the fluent interface more Monadic"?

How to makeJavaScriptMore Monadic?

Lazy vs eager: sometimes it's reasonable to be lazy

Flow control for asynchronous operations is important

Type in some critical places we still need the information

Laws is it possible to follow the Monad Laws?

Requirements to get closer with real Monads

It's easy to make our 'Monad'lazy with some type supporting

var action = (new Maybe()).Just(3) .then((v) => { return (new Maybe()).Just(v+99); }) .then((v) => { return (new Maybe()).Just(v-12); }) .then((v) => { return (new Maybe()).Nothing(); }) .then((v) => { return (new Maybe()).Just(v+12); })

// Execute it with `action.done()`.

action = (Just 3) >>= \v -> return (v + 99) >>= \v -> return (v - 12) >>= \v -> Nothing >>= \v -> return (v + 12)

https://github.com/snowmantw/warmfuzzything.js/blob/master/maybe.js

var action = (new Maybe()).Just(3) .then((v) => { return (new Maybe()).Just(v+99); }) .then((v) => { return (new Maybe()).Just(v-12); }) .then((v) => { return (new Maybe()).Nothing(); }) .then((v) => { return (new Maybe()).Just(v+12); })

// Execute it with `action.done()`.

action = (Just 3) >>= \v -> return (v + 99) >>= \v -> return (v - 12) >>= \v -> Nothing >>= \v -> return (v + 12)

https://github.com/snowmantw/warmfuzzything.js/blob/master/maybe.js

...?

But things become crazy when the 'Monad' need to mix with Promise

(to support async operations natively)

action = (Just 3) >>= \v -> return (v + 99) >>= \v -> return (v - 12) >>= \v -> Nothing >>= \v -> return (v + 12)

https://github.com/snowmantw/warmfuzzything.js/blob/master/promise_maybe.js

var action = (new PromiseMaybe()).Just(3) .then((mSelf, v) => { mSelf.returns((new PromiseMaybe).Just(v+99)); }) .then((mSelf, v) => { setTimeout(function() { // Only for test. Meaningless. mSelf.returns((new PromiseMaybe).Just(v-12)); }, 3000); }) .then((mSelf, v) => { mSelf.returns((new PromiseMaybe).Nothing()); }) .then((mSelf, v) => { mSelf.returns((new PromiseMaybe).Just(v+12)); });

action = (Just 3) >>= \v -> return (v + 99) >>= \v -> return (v - 12) >>= \v -> Nothing >>= \v -> return (v + 12)

https://github.com/snowmantw/warmfuzzything.js/blob/master/promise_maybe.js

var action = (new PromiseMaybe()).Just(3) .then((mSelf, v) => { mSelf.returns((new PromiseMaybe).Just(v+99)); }) .then((mSelf, v) => { setTimeout(function() { // Only for test. Meaningless. mSelf.returns((new PromiseMaybe).Just(v-12)); }, 3000); }) .then((mSelf, v) => { mSelf.returns((new PromiseMaybe).Nothing()); }) .then((mSelf, v) => { mSelf.returns((new PromiseMaybe).Just(v+12)); });

action = (Just 3) >>= \v -> return (v + 99) >>= \v -> return (v - 12) >>= \v -> Nothing >>= \v -> return (v + 12)

https://github.com/snowmantw/warmfuzzything.js/blob/master/promise_maybe.js

var action = (new PromiseMaybe()).Just(3) .then((mSelf, v) => { mSelf.returns((new PromiseMaybe).Just(v+99)); }) .then((mSelf, v) => { setTimeout(function() { // Only for test. Meaningless. mSelf.returns((new PromiseMaybe).Just(v-12)); }, 3000); }) .then((mSelf, v) => { mSelf.returns((new PromiseMaybe).Nothing()); }) .then((mSelf, v) => { mSelf.returns((new PromiseMaybe).Just(v+12)); });

It can be better, but the real problem is it's implementation is very tricky

But the most important things isit works!

But the most important things isit works!

When I see a bird that walks like a Monad and swimslike a Monad and quacks like a Monad, I call that bird a Monad

But the most important things isit works!

(although it doesn't follow the laws)

(although it doesn't follow the laws)

Yes we're still writing JavaScript!

Summary: Monad light the way to isolate side-effects in JavaScript

But how much we gain depends on how much we paid

But how much we gain depends on how much we paid

(or someone must pay it for us)

But how much we gain depends on how much we paid

In my experience the 'simple' fluent interfacewould be not enough soon

"不小心造出個 lexer 的 monad 了,但問題是我在 javascript 阿阿阿" @banacorn

The Missing Part

How to stockpile different Contexts?

The missing part: how to stockpile different Contexts?

List

Request

List

Response

HTTP HTTP

( Request →Response)

The missing part: how to stockpile different Contexts?

List

Request

List

Response

HTTP HTTP

( Request →Response)

(See Appendix. Yes, we have a 200+ slides...)

Part Five.Functional Reactive Programming

TL;DRReact & Flux

So far we discussed how to compose computations rationally

So far we discussed how to compose computations rationally

"But 80% of my work isfor UI changes"

Behavior trigger event

Data changed

View redraw

Let's think about what is an GUI program...

Behavior trigger event

Data changed

View redraw

Let's think about what is an GUI program...

It's so simple, right?

Behavior trigger event

Data changed

View redraw

Let's think about what is an GUI program...

Behavior trigger event

Data changed

View redraw

Let's think about what is an GUI program...

Can be done purely, while

IO is relatively simple than drawing

Lots of side-effects and trolling data anytime

With React we only care about data changes

And 'create' a new view every time it get changed

React.renderComponent(

React.DOM.h1(null, "Hello, world!"),

document.getElementById('example'););

And 'create' a new view every time it get changed

and efficiency is what React should care about

This is like how to manipulate the immutable data structure in FP...

ys = insert ("e", xs)

This is like how to manipulate the immutable data structure in FP...

view' = render(..)

And Flux looks like...

And Flux looks like...

And Flux looks like...

Yampa - a Functional Reactive Programming framework in Haskell

So React & Flux is really close to FP...

It's great because we can build a full Functional Programming stack on it

It's great because we can build a full Functional Programming stack on it

with Function Composition, Monad, Partial Application, Curry, Monad Transformer, and other useful features in JavaScript

Conclusion

We could learn lots from Functional Programming but no need to bet on it

Since we're still with a languagenot so Functional

ex: Composing everything ensuressafety, reusability and flexibility

But the lack of syntax supporting make bitter to be used

High-Order functions is useful, use them whenever it's available

And for list manipulation,native support is ready

Moreover, list transformations are not only for data processing

Functor & Monad is not so terrible: they're just for contexts

And isolate pure & impure computations is good for us

In JavaScript, fluent interface isvery close to Monad

But in current status we don't have a total Monad solution yet

Although when it grows, more and more Monadic features are required

So if your fluent interface code get into troubles of Contexts...

Consider what Monad have and pick up some concepts to implement

Finally, if you want to construct a FP-flavour GUI program

FRP is your friend

React & Flux is your friend

Tools & References

- lo-dash is your friend

- transducer in JavaScript is a good way to understand

reducing deeply

- immutable-js make your code purer

- React & Flux bring you a whole new FRP world

Help and Need Help

Q&A

Appendix

How to stockpiling different Monads

When you have many Monads

HTTP

Request

HTTP

Response

Logger Logger

( Request →Response)

When you have many Monads

HTTP

Request

HTTP

Response

Logger Logger

( Request →Response)

We want to process HTTP as usual

Meanwhile we want every request-response been logged

When you have many Monads

HTTP

Request

HTTP

Response

Database Database

( Request →Response)

We want to process HTTP as usual

Meanwhile we may perform somedatabase R/W at the same time

When you have many Monads

HTTP

Request

HTTP

Response

Error Error

( Request →Response)

We want to process HTTP as usual

Meanwhile we want to capture everystep's error and handle it

Monad Transformer

HTTP

Request

HTTP

Response

m m

>>=

Perform m first (ex: Logger)Then perform the target Monad (HTTP)

It's somewhat of the AOP concept

HTTPTransformer

HTTPLogger

Request

HTTPT (Transformer)

>>=

How Monad Transformer Works

HTTPLogger m

The transformer only know the inner one is the target Monad it can handle withex: (MaybeT → Maybe, HTTPT → HTTP)

Request

HTTPT (Transformer)

>>=

How Monad Transformer Works

HTTPLogger m

The transformer only know the inner one is the target Monad it can handle withex: (MaybeT → Maybe, HTTPT → HTTP)

Request

HTTPT ( "T"ransformer ) would not care what the outer monad is

HTTPT (Transformer)

>>=

How Monad Transformer Works

HTTPLogger m#bind

First transformer would call the outer one's bind function to apply the rule on the inner monadic value, and dig into the second layer (inner monad)Request

apply m#bind on the HTTP monadic value

HTTPT doesn't know what the 'm' is

How Monad Transformer Works

HTTPLogger m#bind

First transformer would call the outer one's bind function to apply the rule on the inner monadic value

Request

apply m#bind on the HTTP monadic value

HTTPT doesn't know what the 'm' is

How Monad Transformer Works

For this example, it means to perform the logging

HTTPLogger m#bind

And then dig into the second layer(inner monad)

Request

apply m#bind on the HTTP monadic value

HTTPT doesn't know what the 'm' is

How Monad Transformer Works

Now we're in the inner monad context

HTTPLogger m Then transformer apply the specific

Monad's binding rules on the inner monadic value, including to call the embedded function, just like what the ordinary Monad does, but now we get(m n b) rather than (m b)

Request Request

HTTP

Response>>=

Logger m

http://en.wikibooks.org/wiki/Haskell/Monad_transformers#A_simple_monad_transformer:_MaybeT

( a → m n b )

How Monad Transformer Works

Step by Step

Outer 'Bind' applied on the monadic value

m (n a) → m (n a)'

Inner 'Bind' applied on the monadic value

m (n a)' → m (n b)

Wrap It Back while it still doesn't know what the m is

m (n a)' → m (n b)

A not so successful try to implement it in JavaScript

PromiseMaybeTNow it can stockpile arbitrary PromiseMonad on one PromiseMaybe monadic action

But since our basic 'Monad' is tricky, the transformer, is tricky, too

https://github.com/snowmantw/warmfuzzything.js/blob/master/maybet.js