$30 off During Our Annual Pro Sale. View Details »

From React To PureScript

Ray Shih
November 29, 2017

From React To PureScript

Ray Shih

November 29, 2017
Tweet

More Decks by Ray Shih

Other Decks in Programming

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