From React To PureScript

2b70ed990e17a78af88b4e3fbd7479e5?s=47 Ray Shih
November 29, 2017

From React To PureScript

2b70ed990e17a78af88b4e3fbd7479e5?s=128

Ray Shih

November 29, 2017
Tweet

Transcript

  1. HOW TO BECOME A BETTER PROGRAMMER FROM REACT TO PURESCRIPT

    RAY SHIH
  2. WHO AM I RAY SHIH • My name is Ray

    Shih • B.S., M.S. of NTU CSIE • Worked in WOOMOO • Worked in Mobiusbobs • Freelancer for now, next stop: FB in London • A Fullstack Software Engineer, including • iOS, Android, Web backend/Frontend • Learn Haskell/PureScript as a hobby :D
  3. BEFORE WE START AGENDA ▸ What is “UI”? And how

    React solve them? ▸ Event handling ▸ View update ▸ Async operations and other side effects ▸ The problems we still have after React. ▸ What does PureScript help? ▸ Some examples of PureScript
  4. WHAT IS “UI”?

  5. https://jsbin.com/caxujex/1/edit?html,js,output

  6. User Clicks Add 1

  7. <button>Click me!</button> <div id=“numDisplay">0</div> $(() => { const display =

    $("#numDisplay") $("button").on('click', () => { display.text(parseInt(display.text()) + 1) }) })
  8. OVERVIEW AGENDA ▸ What is “UI”? And how React solve

    them? ▸ Event handling ▸ View update ▸ Async operations and other side effects ▸ The problems we still have after React. ▸ What does PureScript help? ▸ Some examples of PureScript
  9. $(() => { const display = $("#numDisplay") $("button").on('click', () =>

    { display.text(parseInt(display.text()) + 1) }) }) Event handler registration Event name Event handler callback
  10. $(() => { const display = $("#numDisplay") $("button").on('click', () =>

    { display.text(parseInt(display.text()) + 1) }) }) Anonymous function!!!
 aka callback
 aka arrow function
 aka first class function
  11. COMPARISON: JAVA 7 VS JAVASCRIPT final Button button = findViewById(R.id.button_id);

    button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // Code here executes on main thread // after user presses button } }); $("button").on('click', () => { display.text(parseInt(display.text()) + 1) }) No first class function
 So need a anonymous object First class function: Simple! from https://developer.android.com/reference/android/widget/Button.html
  12. WE HAVE ANONYMOUS FUNCTION IN JAVA 8 BUT NOT FIRST

    CLASS Function<Integer,Integer> add1 = x -> x + 1; Integer two = add1.apply(1); // yields 2 const add1 = x => x + 1 const two = add1(1) First class function: Simple! This is how to invoke a anonymous function in Java 8 https://dzone.com/articles/functional-programming-java-8
  13. FIRST CLASS FUNCTION IS GOOD

  14. BACK TO FIRST CLASS FUNCTION BUT NO CURRY const updateCounter

    = (f, user) => { const { loginCount } = user return { ...user, loginCount: f(loginCount) } } const add = (a, b) => a + b updateCounter(add(1), user) // nope you can't There are some library can do auto curry,
 but often make the type checker fails.
  15. OVERVIEW AGENDA ▸ What is “UI”? And how React solve

    them? ▸ Event handling => First class function ▸ View update ▸ Async operations and other side effects ▸ The problems we still have after React. ▸ What does PureScript help? ▸ Some examples of PureScript
  16. OVERVIEW AGENDA ▸ What is “UI”? And how React solve

    them? ▸ Event handling => First class function ▸ View update ▸ Async operations and other side effects ▸ The problems we still have after React. ▸ What does PureScript help? ▸ Some examples of PureScript
  17. $(() => { const display = $("#numDisplay") $("button").on('click', () =>

    { display.text(parseInt(display.text()) + 1) }) }) No structure. Let’s try MVC?
  18. var num = 0 const display = $("#numDisplay") const render

    = () => display.text(num) $("button").on('click', () => { num += 1 render() }) Model View Controller? https://jsbin.com/caxujex/3/edit?html,js,output
  19. VIEW UPDATE SO WHY REACT? ▸ Hard to synchronize model

    with view ▸ View binding! How? ▸ Re-render entire view! => React render function ▸ Slow? => React VirtualDOM!
  20. // js const render = (model) => { // implementation

    return view } IDEALLY, REACT IS A FUNCTION FROM MODEL TO VIEW
  21. HOW DOES REACT REALLY LOOK LIKE? class Counter extends React.Component

    { constructor() { super() this.state = { num: 0 } this.handleClick = this.handleClick.bind(this) } handleClick() { this.setState({ num: this.state.num + 1 }) } render() { return ( <div> <button onClick={this.handleClick}> Click Me! </button> <div>{this.state.num}</div> </div> ) } } ReactDOM.render( <Counter />, document.getElementById("app") ) https://jsbin.com/leceser/1/edit?html,js,output View Event handler
 and
 Update state Model (state)
  22. VIEW UPDATE REACT IS PERFORMANT! (OR NOT?) ▸ You need

    to implement `shouldComponentUpdate` properly ▸ or use `PureComponent` with ImmutableJS ▸ which implies we need ▸ Immutability ▸ Pure function
  23. VIEW UPDATE REACT IS EASIER TO MAINTAIN! (OR NOT?) ▸

    So we need redux from: https://victorliew.quora.com/A-summary-of-ReactJS-and-Flux
  24. REDUX EXAMPLE const store = Redux.createStore((state = 0, action) =>

    { switch (action.type) { case 'CLICK': return state + 1; default: return state } }) const Counter = ({ num, handleClick }) => ( <div> <button onClick={handleClick}> Click Me! </button> <div>{num}</div> </div> ) const handleClick = () => store.dispatch({ type: 'CLICK' }) const render = () => { ReactDOM.render( <Counter num={store.getState()} handleClick={handleClick} />, document.getElementById("app") ) } store.subscribe(render) render()
  25. REDUX EXAMPLE const store = Redux.createStore((state = 0, action) =>

    { switch (action.type) { case 'CLICK': return state + 1; default: return state } }) const Counter = ({ num, handleClick }) => ( <div> <button onClick={handleClick}> Click Me! </button> <div>{num}</div> </div> ) const handleClick = () => store.dispatch({ type: 'CLICK' }) const render = () => { ReactDOM.render( <Counter num={store.getState()} handleClick={handleClick} />, document.getElementById("app") ) } store.subscribe(render) render() State Action Redux helps developers to separate concern
 But also let developers worry about
 whether the types are matched Current solutions: FlowType, TypeScript Pure Function!
  26. VIEW UPDATE CONFLICTS ▸ It’s hard to combine ImmutableJS with

    FlowType ▸ Ramda is kind of ok with FlowType but very fragile ▸ The problem is type system need to be strong and 100% enforced, otherwise you can’t trust it. ▸ Due to the same reason, FB is building ReasonML.
 Ref: https://youtu.be/tCVXp6gFD8o
  27. OVERVIEW AGENDA ▸ What is “UI”? And how does React

    solve them? ▸ Event handling => First class function ▸ View update => Pure & Static type checker ▸ Async operations and other side effects ▸ The problems we still have after React. ▸ What does PureScript help? ▸ Some examples of PureScript
  28. OVERVIEW AGENDA ▸ What is “UI”? And how does React

    solve them? ▸ Event handling => First class function ▸ View update => Pure & Static type checker ▸ Async operations and other side effects ▸ The problems we still have after React. ▸ What does PureScript help? ▸ Some examples of PureScript
  29. ASYNC OPERATIONS VANILLA JS const queryA = (cb) => {

    ... } const queryB = (a, cb) => { ... } const queryC = (b, cb) => { ... } const dispatch = (a, b, c) => { ... } How to combine those functions?
  30. ASYNC OPERATIONS VANILLA JS const queryA = (cb) => {

    ... } const queryB = (a, cb) => { ... } const queryC = (b, cb) => { ... } const dispatch = (a, b, c) => { ... } const fetch = (cb) => { queryA(a => { queryB(a, b => { queryC(b, c => { dispatch(a, b, c) }) }) }) } Callback Hell!!! How to combine those functions?
  31. ASYNC OPERATIONS PROMISE CAN SOLVE IT (OR CAN’T IT?) const

    fetch = () => queryA().then(a => ( queryB(a).then(b => ( queryC(b).then(c => ( [a, b ,c] )) )) )) .then(([a, b, c]) => { dispatch(a, b, c) }) Callback Hell!!! How to combine those promises?
  32. ASYNC OPERATIONS PROMISE CAN SOLVE IT (OR CAN’T IT?) —

    SECOND TRY Seriously? const fetch = () => queryA() .then(a => queryB(a).then(b => [a, b])) .then(([a, b]) => queryB(b).then(c => [a, b, c])) .then(([a, b, c]) => dispatch(a, b, c)) How to combine those promises?
  33. ASYNC OPERATIONS RX BASED (REDUX OBSERVABLE) const fetch = ()

    => queryA().flatMap(a => ( queryB(a).flatMap(b => ( queryC(b).flatMap(c => ( [a, b, c] )) )) )) .subscribe(([a, b, c]) => { dispatch(a, b, c) }) const fetch = () => queryA().then(a => ( queryB(a).then(b => ( queryC(b).then(c => ( [a, b ,c] )) )) )) .then(([a, b, c]) => { dispatch(a, b, c) }) Really no big difference Similarity between Rx and Promise
 There must be something How to combine those observables?
  34. ASYNC OPERATIONS REDUX SAGA BASED function* fetch() { const a

    = yield call(queryA) const b = yield call(queryB, a) const c = yield call(queryC, b) yield put({ type: 'UPDATE', a, b, c}) } This is what we want right?
 There is also async/await
 but we can actually do more How to combine those ??????
  35. WE NEED A SYNTAX TO COMBINE THOSE SPECIAL THINGS

  36. OVERVIEW AGENDA ▸ What is “UI”? And how React solve

    them? ▸ Event handling => First class function ▸ View update => Pure & Static type checker ▸ Async operations and other side effects
 => ”Special” function composition ▸ The problems we still have after React. ▸ What does PureScript help? ▸ Some examples of PureScript
  37. THE WAY TO FUNCTIONAL PROGRAMMING THINGS WE FOUND USEFUL ▸

    First class function ▸ Purity/Immutable ▸ Static type analysis ▸ “Special” function composition
  38. THE WAY TO FUNCTIONAL PROGRAMMING BUT CURRENT JS ISN’T DOING

    WELL ▸ First class function => No built in curry ▸ Purity/Immutable => No way to guarantee ▸ Static type analysis => None of them are perfect ▸ “Special” function composition => generator kind of does this job, but we can do it better
  39. THE WAY TO FUNCTIONAL PROGRAMMING PURESCRIPT ▸ First class function

    => Checked ▸ Purity/Immutable => Checked ▸ Static type analysis => Checked ▸ “Special” function composition => Checked
  40. OVERVIEW AGENDA ▸ What is “UI”? And how React solve

    them? ▸ Event handling => First class function ▸ View update => Pure & Static type checker ▸ Async operations and other side effects
 => ”Special” function composition ▸ The problems we still have after React. ▸ What does PureScript help? ▸ Some examples of PureScript
  41. PURESCRIPT IS COOL WHAT IS PURESCRIPT ▸ A strongly-typed functional

    programming language that compiles to JavaScript!
  42. PURESCRIPT IS COOL WHAT IS PURESCRIPT ▸ A strongly-typed ▸

    functional programming language, that ▸ compiles to JavaScript! ▸ Think about CoffeeScript, TypeScript, Babel…etc ▸ Yup PureScript is one of them
  43. OVERVIEW AGENDA ▸ What is “UI”? And how React solve

    them? ▸ Event handling => First class function ▸ View update => Pure & Static type checker ▸ Async operations and other side effects
 => ”Special” function composition ▸ The problems we still have after React. ▸ What does PureScript help? ▸ Some examples of PureScript
  44. PURESCRIPT EXAMPLES CURRY? OR “I DON’T CARE”? add :: Int

    -> Int -> Int add a b = a + b arr = [1, 2, 3] map (add 1) arr -- [2, 3, 4] In PureScript In JS const add = (a: number) => (b: number): number => a + b const arr = [1, 2, 3] arr.map(add(1))
  45. None
  46. PURESCRIPT EXAMPLES PURITY/IMMUTABLE ▸ There is no variable => you

    can’t change anything ▸ Immutable (of course) ▸ Pure function (of course) ▸ The interesting part: ▸ Pure function doesn’t limit you to do anything
  47. PURESCRIPT EXAMPLES STATIC TYPE ANALYSIS ▸ PureScript is a compiled

    language with ▸ Hindley-Milner type system ▸ Same as Haskell ▸ “if a Haskell program compiles, it probably works"
  48. PURESCRIPT EXAMPLES ASYNC OPERATIONS AND OTHER SIDE EFFECTS 1 —

    ASYNC QUERY In PureScript In JS function* fetch() { const a = yield call(queryA) const b = yield call(queryB, a) const c = yield call(queryC, b) yield put({ type: 'UPDATE', a, b, c}) } fetch = do a <- queryA b <- queryB a c <- queryC b dispatch a b c
  49. PURESCRIPT EXAMPLES ASYNC OPERATIONS AND OTHER SIDE EFFECTS 2 —

    MAYBE In PureScript In JS const getGreatGrandParent = person => { const parent = getParent(person) if (parent == null) return null const grandParent = getParent(parent) if (grandParent == null) return null return getParent(grandParent) } getGreatGrandParent person = do parent <- getParent person grandParent <- getParent parent getParent grandParent
  50. PURESCRIPT EXAMPLES ASYNC OPERATIONS AND OTHER SIDE EFFECTS 3 —

    LIST In PureScript In JS const getGreatGrandChildren = person => getChildren(person) .map(getChildren).flatten() .map(getChildren).flatten() getGreatGrandChildren person = do child <- getChildren person grandChild <- getChildren child getChildren grandChild
  51. AND MANY MORE

  52. MORE JAVASCRIPT INTEROPERATION ▸ It actually compiles to JavaScript without

    runtime ▸ Can invoke JS function (after annotate the type) ▸ So you can use PureScript partially
  53. LET’S LEARN HOW TO START? ▸ Books! ▸ PureScript by

    Example ▸ Learn you a Haskell ▸ Find a mentor ▸ Join a study group ▸ https://try.purescript.org
  54. JUST TRY IT SERIOUSLY, HOW TO START? ▸ npm install

    -g purescript pulp bower ▸ mkdir purescript-hello ▸ cd purescript-hello ▸ pulp init ▸ pulp run
  55. JUST TRY IT SOME LIBRARIES ▸ Pux — almost like

    redux ▸ e.g. https://github.com/rayshih/pux-todomvc ▸ Lens — cool library to operate on nested data and more ▸ Async — you need this to perform async tasks ▸ Simple JSON — the easiest way to parse JSON safely
  56. MY SECRET HOW TO LEARN OOP WELL The secret is:

    learn functional programming https://www.slideshare.net/ScottWlaschin/fp-patterns-buildstufflt
  57. THANKS AND Q&A