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

JSDC 2014 - functional java script, why or why not

Apr 16, 2017

Download

ChengHui Weng
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: JSDC 2014 - functional java script, why or why not

Functional JavaScript, Why or Why Not?

JSDC 2014

bit.ly/jsdc2014-funjs

Page 2: JSDC 2014 - functional java script, why or why not

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Page 3: JSDC 2014 - functional java script, why or why not

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Page 4: JSDC 2014 - functional java script, why or why not

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Page 5: JSDC 2014 - functional java script, why or why not

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Page 6: JSDC 2014 - functional java script, why or why not

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Page 7: JSDC 2014 - functional java script, why or why not

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Page 8: JSDC 2014 - functional java script, why or why not

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Page 9: JSDC 2014 - functional java script, why or why not

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Page 10: JSDC 2014 - functional java script, why or why not

Hi, I'm Greg WengFrom Mozilla Taiwan

@GregWengabout.me/snowmantw

Page 11: JSDC 2014 - functional java script, why or why not

Motivation

Page 12: JSDC 2014 - functional java script, why or why not
Page 13: JSDC 2014 - functional java script, why or why not

Outline

Page 14: JSDC 2014 - functional java script, why or why not

This talk is about

ConceptsFeaturesTrade-OffLibrariesFrameworks

Page 15: JSDC 2014 - functional java script, why or why not

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?

Page 16: JSDC 2014 - functional java script, why or why not

Premise

No Compiler(No magic!)

Page 17: JSDC 2014 - functional java script, why or why not

Concepts

Page 18: JSDC 2014 - functional java script, why or why not

Functional Programming?

Page 19: JSDC 2014 - functional java script, why or why not

Which one is better?

Page 20: JSDC 2014 - functional java script, why or why not

Which one is better?more useful?

OOP FP

Page 21: JSDC 2014 - functional java script, why or why not

Functional Programming is about

PurityContextEvaluationCompositionTransformation

Page 22: JSDC 2014 - functional java script, why or why not

It would bring you

Re-thinking about programming

Patterns efficiently make your works done

Fun -citons

Page 23: JSDC 2014 - functional java script, why or why not

Features of Functional Programmings

First-class function | Closure

High-order functions | Function composition

Purity | Managed side-effects | Laziness

Recursion | Tail-recursion optimization | (Type)

Page 24: JSDC 2014 - functional java script, why or why not

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...

Page 25: JSDC 2014 - functional java script, why or why not

function() {} is everything

Page 26: JSDC 2014 - functional java script, why or why not

function() {} is everything

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

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

Page 27: JSDC 2014 - functional java script, why or why not

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)

Page 28: JSDC 2014 - functional java script, why or why not

About the signature

Array Number → (Number → String) → Array String

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

"return value"function as argumentargument

a, b: type variables

Page 29: JSDC 2014 - functional java script, why or why not

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

But what about...

Page 30: JSDC 2014 - functional java script, why or why not

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

But what about...

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

Page 31: JSDC 2014 - functional java script, why or why not

Immutable Data Structure

Page 32: JSDC 2014 - functional java script, why or why not

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

Page 33: JSDC 2014 - functional java script, why or why not

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

Page 34: JSDC 2014 - functional java script, why or why not

So now we have the Transformation

Page 35: JSDC 2014 - functional java script, why or why not

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

Page 36: JSDC 2014 - functional java script, why or why not

So now we have the Transformation

ba

Page 37: JSDC 2014 - functional java script, why or why not

But we need to Composethem together

Page 38: JSDC 2014 - functional java script, why or why not

Part One.High-Order Functions

Page 39: JSDC 2014 - functional java script, why or why not

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

Page 40: JSDC 2014 - functional java script, why or why not

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

Page 41: JSDC 2014 - functional java script, why or why not

Receive functions as arguments

Page 42: JSDC 2014 - functional java script, why or why not

High-Order Functions is useful

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

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

Page 43: JSDC 2014 - functional java script, why or why not

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

Page 44: JSDC 2014 - functional java script, why or why not

No more looping & ijk tricks

Page 45: JSDC 2014 - functional java script, why or why not

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

Page 46: JSDC 2014 - functional java script, why or why not

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

Page 47: JSDC 2014 - functional java script, why or why not

It's not only about SLOC

Page 48: JSDC 2014 - functional java script, why or why not

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...

Page 49: JSDC 2014 - functional java script, why or why not

reduce:: [a] → b

Page 50: JSDC 2014 - functional java script, why or why not

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

Page 51: JSDC 2014 - functional java script, why or why not

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...

Page 52: JSDC 2014 - functional java script, why or why not

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

Page 53: JSDC 2014 - functional java script, why or why not

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

Page 54: JSDC 2014 - functional java script, why or why not

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

If there is no or only few side-effects

Page 55: JSDC 2014 - functional java script, why or why not

It can be more powerful if you play with the type

Page 56: JSDC 2014 - functional java script, why or why not

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

Page 57: JSDC 2014 - functional java script, why or why not

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

while a/URL, b/IO

Page 58: JSDC 2014 - functional java script, why or why not

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

Page 59: JSDC 2014 - functional java script, why or why not

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

Page 60: JSDC 2014 - functional java script, why or why not

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]

Page 61: JSDC 2014 - functional java script, why or why not

Not only handle data

Page 62: JSDC 2014 - functional java script, why or why not

Some advanced High-OrderFunctions of list

Page 63: JSDC 2014 - functional java script, why or why not

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

Page 64: JSDC 2014 - functional java script, why or why not

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

Page 65: JSDC 2014 - functional java script, why or why not

And reducing is even more basic

Page 66: JSDC 2014 - functional java script, why or why not

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

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

Page 67: JSDC 2014 - functional java script, why or why not

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

Page 68: JSDC 2014 - functional java script, why or why not

Do map & reduce wheneverit's possible

Page 69: JSDC 2014 - functional java script, why or why not

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

Page 70: JSDC 2014 - functional java script, why or why not

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

We'll see more cases soon

Page 71: JSDC 2014 - functional java script, why or why not

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

Page 72: JSDC 2014 - functional java script, why or why not

Part Two.Function Composition

Page 73: JSDC 2014 - functional java script, why or why not

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

Page 74: JSDC 2014 - functional java script, why or why not

Instead, we compose themwhen we need it

Page 75: JSDC 2014 - functional java script, why or why not

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

Page 76: JSDC 2014 - functional java script, why or why not

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

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

Page 77: JSDC 2014 - functional java script, why or why not

Is much better than

Page 78: JSDC 2014 - functional java script, why or why not

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

Page 79: JSDC 2014 - functional java script, why or why not

let notOdd x = not(odd x);

map notOdd [1,2,3]

Page 80: JSDC 2014 - functional java script, why or why not

This is important because

Page 81: JSDC 2014 - functional java script, why or why not

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

Page 82: JSDC 2014 - functional java script, why or why not

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

Page 83: JSDC 2014 - functional java script, why or why not

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

Page 84: JSDC 2014 - functional java script, why or why not

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

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

...?

Page 85: JSDC 2014 - functional java script, why or why not

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

Page 86: JSDC 2014 - functional java script, why or why not

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

Page 87: JSDC 2014 - functional java script, why or why not

with the only one 'operator' we have

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

Page 88: JSDC 2014 - functional java script, why or why not

Part Three.Context & Functor

Page 89: JSDC 2014 - functional java script, why or why not

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

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

Page 90: JSDC 2014 - functional java script, why or why not

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

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

Page 91: JSDC 2014 - functional java script, why or why not

m a → (a → b) → m b

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

Page 92: JSDC 2014 - functional java script, why or why not

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

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

Page 93: JSDC 2014 - functional java script, why or why not

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

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

Page 94: JSDC 2014 - functional java script, why or why not

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

Page 95: JSDC 2014 - functional java script, why or why not

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

Page 96: JSDC 2014 - functional java script, why or why not

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

Page 97: JSDC 2014 - functional java script, why or why not

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'

Page 98: JSDC 2014 - functional java script, why or why not

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

Page 99: JSDC 2014 - functional java script, why or why not

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

Page 100: JSDC 2014 - functional java script, why or why not

Type classes with fmap calledFunctor

Page 101: JSDC 2014 - functional java script, why or why not

Functor can lift a functiononto the context

Page 102: JSDC 2014 - functional java script, why or why not

m

a

m

b( a → b)

fmap

Page 103: JSDC 2014 - functional java script, why or why not

The function keep knowing nothing about the Context

Page 104: JSDC 2014 - functional java script, why or why not

m

a

m

b( a → b)

$(not, odd, read)

fmap

Page 105: JSDC 2014 - functional java script, why or why not

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

Page 106: JSDC 2014 - functional java script, why or why not

How to apply context-relevant rules is encapsulated by fmap

Page 107: JSDC 2014 - functional java script, why or why not

$(not, odd, read)

List

a

List

b( a → b)

List#fmapapply the function on every element of the list

fmap

Page 108: JSDC 2014 - functional java script, why or why not

$(not, odd, read)

HTTP

a

HTTP

b( a → b)

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

fmap

Page 109: JSDC 2014 - functional java script, why or why not

$(not, odd, read)

Maybe

a

Maybe

b( a → b)

fmap

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

Page 110: JSDC 2014 - functional java script, why or why not

This is powerful because we can keep functions simple

Page 111: JSDC 2014 - functional java script, why or why not

And apply them into different context to do different things

Page 112: JSDC 2014 - functional java script, why or why not

HTTP

Request

HTTP

Response( Request →Response)

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

Page 113: JSDC 2014 - functional java script, why or why not

List

Request

List

Response( Request → Response)

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

Page 114: JSDC 2014 - functional java script, why or why not

Contexts could even be stockpiled to do complex computations

Page 115: JSDC 2014 - functional java script, why or why not

Contexts could even be stockpiled to do complex computations

Although stockpiling is beyond Functor. See Appendix: Monad Transformer

Page 116: JSDC 2014 - functional java script, why or why not

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.

Page 117: JSDC 2014 - functional java script, why or why not

And the stockpiling orderis very important

Page 118: JSDC 2014 - functional java script, why or why not

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?)

Page 119: JSDC 2014 - functional java script, why or why not

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.

Page 120: JSDC 2014 - functional java script, why or why not

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

Page 121: JSDC 2014 - functional java script, why or why not

But we still need more powerful structure to do the computation

Page 122: JSDC 2014 - functional java script, why or why not

Part Four.Monad

Page 123: JSDC 2014 - functional java script, why or why not

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

Page 124: JSDC 2014 - functional java script, why or why not
Page 125: JSDC 2014 - functional java script, why or why not
Page 126: JSDC 2014 - functional java script, why or why not
Page 127: JSDC 2014 - functional java script, why or why not
Page 128: JSDC 2014 - functional java script, why or why not
Page 129: JSDC 2014 - functional java script, why or why not
Page 130: JSDC 2014 - functional java script, why or why not

Monad, monad, everywhere, nor any drop to understand

Page 131: JSDC 2014 - functional java script, why or why not

Monad is a solution forcomposing Context-ed actions

Page 132: JSDC 2014 - functional java script, why or why not

In Functor we can only transform pure data to pure data

Page 133: JSDC 2014 - functional java script, why or why not

HTTP

Request

HTTP

Response( Request →Response)

( a → b )

Page 134: JSDC 2014 - functional java script, why or why not

We may have different sub-contexts for HTTP

Page 135: JSDC 2014 - functional java script, why or why not

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

Page 136: JSDC 2014 - functional java script, why or why not

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

Page 137: JSDC 2014 - functional java script, why or why not

HTTP

Request

HTTP::200

Response( Request →Response)

( a → b )

Page 138: JSDC 2014 - functional java script, why or why not

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

Page 139: JSDC 2014 - functional java script, why or why not

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

Page 140: JSDC 2014 - functional java script, why or why not

Monad allows you to do that withits 'bind' function

Page 141: JSDC 2014 - functional java script, why or why not

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

Page 142: JSDC 2014 - functional java script, why or why not

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

a → m b m a

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

Page 143: JSDC 2014 - functional java script, why or why not

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

Page 144: JSDC 2014 - functional java script, why or why not

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

True -> content False -> authError))

Page 145: JSDC 2014 - functional java script, why or why not

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

True -> content False -> authError))

the 'bind' function, infix

HTTP::403

HTTP::200

Page 146: JSDC 2014 - functional java script, why or why not

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

True -> content False -> authError)

( a → m b )

Page 147: JSDC 2014 - functional java script, why or why not

How 'bind' works?

Page 148: JSDC 2014 - functional java script, why or why not

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

Client ClientHTTP Monad

Page 149: JSDC 2014 - functional java script, why or why not

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)

Page 150: JSDC 2014 - functional java script, why or why not

We still keep the same interface, different implementations feature

Page 151: JSDC 2014 - functional java script, why or why not

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

Client ClientHTTP Monad

Page 152: JSDC 2014 - functional java script, why or why not

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

Map to all elements

Map to all elements

List Monad

Page 153: JSDC 2014 - functional java script, why or why not

And the Monadic actions can be chained as function composition

Page 154: JSDC 2014 - functional java script, why or why not

a → m c

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

Page 155: JSDC 2014 - functional java script, why or why not

a → m c

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

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

(and so on...)

Page 156: JSDC 2014 - functional java script, why or why not

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

Page 157: JSDC 2014 - functional java script, why or why not

h = g 。f

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

a → c = b → c 。 a → b

Page 158: JSDC 2014 - functional java script, why or why not

And Monad could save us from unexpected side-effects

Page 159: JSDC 2014 - functional java script, why or why not

And Monad could save us from unexpected side-effects

if all methods with side-effectsare wrapped

Page 160: JSDC 2014 - functional java script, why or why not

getStringforkIO

openFile readTVar

+, -, *...compress

tailpar

writeArray

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

a → b

Page 161: JSDC 2014 - functional java script, why or why not

getStringforkIO

openFile readTVar

+, -, *...compress

tailpar

writeArray

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

a → b

Embed them rationallywith the 'bind' function

Page 162: JSDC 2014 - functional java script, why or why not

So we can combine these functions and Contexts rationally

Page 163: JSDC 2014 - functional java script, why or why not

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

line: 290 ~ 490 (200 lines)

Page 164: JSDC 2014 - functional java script, why or why not

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

...

Page 165: JSDC 2014 - functional java script, why or why not

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

line: 290 ~ 490 (200 lines)

There are so many

requests

from so many different

contexts

Page 166: JSDC 2014 - functional java script, why or why not

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

Page 167: JSDC 2014 - functional java script, why or why not

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

...

Page 168: JSDC 2014 - functional java script, why or why not

This is important because no one like surprises

Page 169: JSDC 2014 - functional java script, why or why not
Page 170: JSDC 2014 - functional java script, why or why not

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

Page 171: JSDC 2014 - functional java script, why or why not

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

Page 172: JSDC 2014 - functional java script, why or why not

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

Page 173: JSDC 2014 - functional java script, why or why not

There is no way allowa Context-ed value to escape

Page 174: JSDC 2014 - functional java script, why or why not

There is no way allowa Context-ed value to escape

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

Page 175: JSDC 2014 - functional java script, why or why not

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

Page 176: JSDC 2014 - functional java script, why or why not
Page 177: JSDC 2014 - functional java script, why or why not

Instead, you embed your function into the tainted context

Page 178: JSDC 2014 - functional java script, why or why not

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

True -> content False -> authError))

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

Page 179: JSDC 2014 - functional java script, why or why not

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

True -> content False -> authError))

let HTTPValue =

doSomething HTTPValue ...No way to do that!

extract

Page 180: JSDC 2014 - functional java script, why or why not

The similar case in JavaScript is the Promised actions

Page 181: JSDC 2014 - functional java script, why or why not

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

var promisedValue =

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

Page 182: JSDC 2014 - functional java script, why or why not

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

Page 183: JSDC 2014 - functional java script, why or why not

But the idea to control different computations in different Contexts

Page 184: JSDC 2014 - functional java script, why or why not

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

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

Page 185: JSDC 2014 - functional java script, why or why not

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

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

Page 186: JSDC 2014 - functional java script, why or why not

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

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

Page 187: JSDC 2014 - functional java script, why or why not

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

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

Page 188: JSDC 2014 - functional java script, why or why not

These computations focus on the transforming within the contexts

Page 189: JSDC 2014 - functional java script, why or why not

Just like what Monadsdo in Haskell

Page 190: JSDC 2014 - functional java script, why or why not

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

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

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

DOM _Async

Page 191: JSDC 2014 - functional java script, why or why not

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

Page 192: JSDC 2014 - functional java script, why or why not

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

Page 193: JSDC 2014 - functional java script, why or why not

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

Page 194: JSDC 2014 - functional java script, why or why not

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

Page 195: JSDC 2014 - functional java script, why or why not

How to makeJavaScriptMore Monadic?

Page 196: JSDC 2014 - functional java script, why or why not

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

Page 197: JSDC 2014 - functional java script, why or why not

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

Page 198: JSDC 2014 - functional java script, why or why not

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

Page 199: JSDC 2014 - functional java script, why or why not

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

...?

Page 200: JSDC 2014 - functional java script, why or why not

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

(to support async operations natively)

Page 201: JSDC 2014 - functional java script, why or why not

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)); });

Page 202: JSDC 2014 - functional java script, why or why not

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)); });

Page 203: JSDC 2014 - functional java script, why or why not

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

Page 204: JSDC 2014 - functional java script, why or why not

But the most important things isit works!

Page 205: JSDC 2014 - functional java script, why or why not

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

Page 206: JSDC 2014 - functional java script, why or why not

But the most important things isit works!

(although it doesn't follow the laws)

Page 207: JSDC 2014 - functional java script, why or why not

(although it doesn't follow the laws)

Page 208: JSDC 2014 - functional java script, why or why not

Yes we're still writing JavaScript!

Page 209: JSDC 2014 - functional java script, why or why not

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

Page 210: JSDC 2014 - functional java script, why or why not

But how much we gain depends on how much we paid

Page 211: JSDC 2014 - functional java script, why or why not

But how much we gain depends on how much we paid

(or someone must pay it for us)

Page 212: JSDC 2014 - functional java script, why or why not

But how much we gain depends on how much we paid

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

Page 213: JSDC 2014 - functional java script, why or why not

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

Page 214: JSDC 2014 - functional java script, why or why not

The Missing Part

Page 215: JSDC 2014 - functional java script, why or why not

How to stockpile different Contexts?

Page 216: JSDC 2014 - functional java script, why or why not

The missing part: how to stockpile different Contexts?

List

Request

List

Response

HTTP HTTP

( Request →Response)

Page 217: JSDC 2014 - functional java script, why or why not

The missing part: how to stockpile different Contexts?

List

Request

List

Response

HTTP HTTP

( Request →Response)

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

Page 218: JSDC 2014 - functional java script, why or why not

Part Five.Functional Reactive Programming

Page 219: JSDC 2014 - functional java script, why or why not

TL;DRReact & Flux

Page 220: JSDC 2014 - functional java script, why or why not

So far we discussed how to compose computations rationally

Page 221: JSDC 2014 - functional java script, why or why not

So far we discussed how to compose computations rationally

Page 222: JSDC 2014 - functional java script, why or why not

"But 80% of my work isfor UI changes"

Page 223: JSDC 2014 - functional java script, why or why not

Behavior trigger event

Data changed

View redraw

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

Page 224: JSDC 2014 - functional java script, why or why not

Behavior trigger event

Data changed

View redraw

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

It's so simple, right?

Page 225: JSDC 2014 - functional java script, why or why not

Behavior trigger event

Data changed

View redraw

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

Page 226: JSDC 2014 - functional java script, why or why not

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

Page 227: JSDC 2014 - functional java script, why or why not

With React we only care about data changes

Page 228: JSDC 2014 - functional java script, why or why not

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

Page 229: JSDC 2014 - functional java script, why or why not

React.renderComponent(

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

document.getElementById('example'););

Page 230: JSDC 2014 - functional java script, why or why not

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

and efficiency is what React should care about

Page 231: JSDC 2014 - functional java script, why or why not

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

ys = insert ("e", xs)

Page 232: JSDC 2014 - functional java script, why or why not

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

view' = render(..)

Page 233: JSDC 2014 - functional java script, why or why not

And Flux looks like...

Page 234: JSDC 2014 - functional java script, why or why not

And Flux looks like...

Page 235: JSDC 2014 - functional java script, why or why not

And Flux looks like...

Yampa - a Functional Reactive Programming framework in Haskell

Page 236: JSDC 2014 - functional java script, why or why not

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

Page 237: JSDC 2014 - functional java script, why or why not

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

Page 238: JSDC 2014 - functional java script, why or why not
Page 239: JSDC 2014 - functional java script, why or why not

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

Page 240: JSDC 2014 - functional java script, why or why not

Conclusion

Page 241: JSDC 2014 - functional java script, why or why not

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

Page 242: JSDC 2014 - functional java script, why or why not

Since we're still with a languagenot so Functional

Page 243: JSDC 2014 - functional java script, why or why not

ex: Composing everything ensuressafety, reusability and flexibility

Page 244: JSDC 2014 - functional java script, why or why not

But the lack of syntax supporting make bitter to be used

Page 245: JSDC 2014 - functional java script, why or why not

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

Page 246: JSDC 2014 - functional java script, why or why not

And for list manipulation,native support is ready

Page 247: JSDC 2014 - functional java script, why or why not

Moreover, list transformations are not only for data processing

Page 248: JSDC 2014 - functional java script, why or why not

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

Page 249: JSDC 2014 - functional java script, why or why not

And isolate pure & impure computations is good for us

Page 250: JSDC 2014 - functional java script, why or why not

In JavaScript, fluent interface isvery close to Monad

Page 251: JSDC 2014 - functional java script, why or why not

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

Page 252: JSDC 2014 - functional java script, why or why not

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

Page 253: JSDC 2014 - functional java script, why or why not

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

Page 254: JSDC 2014 - functional java script, why or why not

Consider what Monad have and pick up some concepts to implement

Page 255: JSDC 2014 - functional java script, why or why not

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

Page 256: JSDC 2014 - functional java script, why or why not

FRP is your friend

Page 257: JSDC 2014 - functional java script, why or why not

React & Flux is your friend

Page 258: JSDC 2014 - functional java script, why or why not

Tools & References

Page 259: JSDC 2014 - functional java script, why or why not

- 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

Page 261: JSDC 2014 - functional java script, why or why not

Help and Need Help

Page 262: JSDC 2014 - functional java script, why or why not
Page 264: JSDC 2014 - functional java script, why or why not

Q&A

Page 265: JSDC 2014 - functional java script, why or why not

Appendix

Page 266: JSDC 2014 - functional java script, why or why not

How to stockpiling different Monads

Page 268: JSDC 2014 - functional java script, why or why not

When you have many Monads

HTTP

Request

HTTP

Response

Logger Logger

( Request →Response)

Page 269: JSDC 2014 - functional java script, why or why not

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

Page 270: JSDC 2014 - functional java script, why or why not

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

Page 271: JSDC 2014 - functional java script, why or why not

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

Page 272: JSDC 2014 - functional java script, why or why not

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

Page 273: JSDC 2014 - functional java script, why or why not

HTTPLogger

Request

HTTPT (Transformer)

>>=

How Monad Transformer Works

Page 274: JSDC 2014 - functional java script, why or why not

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

Page 275: JSDC 2014 - functional java script, why or why not

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

Page 276: JSDC 2014 - functional java script, why or why not

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

Page 277: JSDC 2014 - functional java script, why or why not

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

Page 278: JSDC 2014 - functional java script, why or why not

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

Page 279: JSDC 2014 - functional java script, why or why not

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

Page 280: JSDC 2014 - functional java script, why or why not

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)

Page 281: JSDC 2014 - functional java script, why or why not

A not so successful try to implement it in JavaScript

Page 283: JSDC 2014 - functional java script, why or why not

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