Upgrade to Pro — share decks privately, control downloads, hide ads and more …

C'est qui Reason(ML) et qu'est ce qu'il fait là?

C'est qui Reason(ML) et qu'est ce qu'il fait là?

Maxime Thirouin

November 20, 2018
Tweet

More Decks by Maxime Thirouin

Other Decks in Technology

Transcript

  1. @MoOx What redux does, ReasonReact and Elm do 4 Actions

    are types, reducers are functions,
 state is immutable, but at the language level Previously in React Toulouse…
  2. @MoOx 10 add(1, 1); // 2 add(1, "1"); // "11"

    add(1, null); // 1 add(1, undefined); // NaN
  3. @MoOx We covers what we think about. 18 And we

    are developers. And we make mistakes
  4. @MoOx 21 1. A language 2. A syntax 3. A

    compiler 4. An ecosystem
  5. @MoOx let rec map f = function [] -> []

    | a::l -> let r = f a in r :: map f l 25
  6. @MoOx 28 let add a b = a + b

    let add = (a, b) => a + b; ML RE
  7. @MoOx 29 1. A language 2. A syntax 3. A

    compiler 4. An ecosystem
  8. @MoOx 33 1. A language 2. A syntax 3. A

    compiler 4. An ecosystem
  9. @MoOx 37 BASICS 1; /* int */ 1.0; /* float

    */ "Hello"; /* string */ 'H'; /* char */ true; /* bool */
  10. @MoOx 38 BASICS [1, 2, 3]; /* list(int) */ [|1,

    2, 3|]; /* array(int) */ Some(x); /* option('a) */ () /* unit */
  11. @MoOx 39 RECORDS let me = { name: "Matthias", age:

    24, }; let meLater = { ...me, age: 25, }; type user = { name: string, age: int, }; You declare the type of the record You can create records of this type You can create spread values to create a new record from a previous one
  12. @MoOx 41 App.re MODULES Every file is a module and

    filenames are unique Welcome.re let sayHi = (name) => Js.log("Hi " ++ name ++ "!"); Welcome.sayHi("people"); Every top level binding is exported by default To open a module, just use its capitalised name
  13. @MoOx 42 MODULES module Talk { include Presentation; let slides

    = ["a", "b", "c"]; let slidesWithIndex = slides ->Belt.List.mapWithIndex((index, item) => (index, item)); }; open OtherModule; Declare a module within a module Include modules like a static extends Make all module available in scope
  14. @MoOx 44 FUNCTIONS let add = (a, b) => a

    + b; let addDoubles = (a, b) => { let doubleA = a * 2; let doubleB = b * 2; doubleA + doubleB; }; Every function has its signature let add: (int, int) => int = <fun>; Last expression is the returned value
  15. @MoOx 45 FUNCTIONS Pipe operator! Functions are auto curried That

    means that they return a function taking the rest of the arguments as long as you didn't pass all the required ones [1, 2, 3] ->Belt.List.keep(item => item mod 2 === 0) ->Belt.List.map(item => item * 2);
  16. @MoOx 46 FUNCTIONS let make = ( ~rootPath="./", ~fileExtensions=["re", "js"],

    ~watch=false, ~onChange=?, () ) => { /* ... */ }; Functions can have labelled arguments Their order at function application doesn't mater Optionals Default values Final non labelled argument When you have optional arguments, this tells the compiler «I have all the arguments there»
  17. @MoOx 48 WHAT'S WRONG WITH THIS? type state = {

    isLoading: false, hasErrored: false, data: null, };
  18. @MoOx 49 IMPOSSIBLE STATES ARE ACTUALLY POSSIBLE isLoading hasErrored data

    FALSE FALSE NULL TRUE FALSE NULL FALSE TRUE NULL TRUE TRUE NULL FALSE FALSE DATA TRUE FALSE DATA FALSE TRUE DATA TRUE TRUE DATA NotAsked Loading Errored Loaded
  19. @MoOx 50 THE SOLUTION: VARIANTS type t('a) = | NotAsked

    | Loading | Loaded('a) | Errored; A variant type is a «OR» type A type can be parametrised aka Generics Every constructor can hold data like a container type
  20. @MoOx 51 THE SOLUTION: VARIANTS switch (resource) { | NotAsked

    => "" | Loading => "Loading ..." | Loaded(value) => "Loaded: " ++ value | Errored => "An error occurred" }; You use pattern matching to extract values
  21. @MoOx 52 THE SOLUTION: VARIANTS switch (resource) { | NotAsked

    => "" | Loading => "Loading ..." | Loaded(value) => "Loaded: " ++ value }; Warning 8: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: Errored
  22. @MoOx 53 THERE'S NO NULL type option('a) = | Some('a)

    | None; switch (value) { | Some(value) => value | None => "Nothing to see" }; Move null checks at compile time If it's maybe a value, you need to handle it explicitly
  23. @MoOx 55 LIST IS A VARIANT TYPE type list('a) =

    | Empty | Head('a, list('a)); let list = Head(1, Head(2, Head(3, Empty)));
  24. @MoOx 56 LIST IS A VARIANT TYPE If there's nothing

    left Return empty Return a head with transformed item then transform the rest with a recursive call Recursive let rec map = (f, list) => switch (list) { | Empty => Empty | Head(x, rest) => Head(f(x), map(f, rest)) };
  25. @MoOx 57 LIST IS A VARIANT TYPE Reassigned Reassigned let

    foldLeft = (array, f, acc) => { let index = -1; while(++index < array.length) { acc = f(acc, array[index]) }; return acc };
  26. @MoOx 58 ACTUALLY IN JS // http://es5.github.io/#x15.4.4.21 function foldLeft(arr, fn)

    { var array = new Object(arr), index = -1, length = array.length >>> 0, acc, hasInitialValue; if (Object.prototype.toString.call(fn) != "[object Function]") { throw new TypeError(); } if (arguments.length > 1) { acc = arguments[1]; } else { hasInitialValue = false; while (++index < length) { if (!(hasInitialValue = index in array)) { continue; } acc = array[index]; break; } if (!hasInitialValue) { throw new TypeError(); } } while (++index < length) { if (!(index in array)) continue; acc = fn.call(void 0, acc, array[index], index, array); } return acc; };
  27. @MoOx 59 ACTUALLY IN JS: DYNAMIC TYPING // http://es5.github.io/#x15.4.4.21 function

    foldLeft(arr, fn) { var array = new Object(arr), index = -1, length = array.length >>> 0, acc, hasInitialValue; if (Object.prototype.toString.call(fn) != "[object Function]") { throw new TypeError(); } if (arguments.length > 1) { acc = arguments[1]; } else { hasInitialValue = false; while (++index < length) { if (!(hasInitialValue = index in array)) { continue; } acc = array[index]; break; } if (!hasInitialValue) { throw new TypeError(); } } while (++index < length) { if (!(index in array)) continue; acc = fn.call(void 0, acc, array[index], index, array); } return acc; };
  28. @MoOx 60 LIST IS A VARIANT TYPE let rec fold_left

    = (f, acc, list) => switch (list) { | [] => acc | [x, ...rest] => fold_left(f, f(acc, x), rest) };
  29. @MoOx 63 INTEROP: EXTERNAL MODULES [@bs.module "../myExistingJsModule"] external myExistingJsModule :

    string = ""; Declare that it's a module located at "../myExistingModule" The module is of string type Js.log(myExistingJsModule); The module is only imported when used
  30. @MoOx 64 INTEROP: EXTERNAL MODULES // Generated by BUCKLESCRIPT VERSION

    2.2.4, PLEASE EDIT WITH CARE 'use strict'; var MyExistingJsModule = require("../myExistingJsModule"); console.log(MyExistingJsModule.myExistingJsModule); /* Not a pure module */
  31. @MoOx 65 INTEROP: CREATE AND READ JAVASCRIPT OBJECTS let myJsObject

    = { "name": "Matthias", "age": Js.Null.return(24) }; Js.log(myJsObject##name);
  32. @MoOx 70 WHERE DOES REACT COME FROM? Creator of React

    Jordan Walke wrote the first React prototype in SML
  33. @MoOx 71 REASONREACT HAS A LOT BAKED IN • Components

    • Router • Reducers • Subscriptions
  34. @MoOx 73 REASONREACT: BASIC COMPONENT let component = ReasonReact.statelessComponent("HelloWorld"); let

    make = (~name, _children) => { ...component, render: (_self) => <div> (ReasonReact.string("Hello " ++ name)) </div> };
  35. @MoOx 74 REASONREACT: REDUCER COMPONENT Define the type of the

    state Define all possible actions type state = int; type action = | Increment | Decrement; let component = ReasonReact.reducerComponent("Counter");
  36. @MoOx 75 REASONREACT: REDUCER COMPONENT Return an update for each

    action can be Update, UpdateWithSideEffect, SideEffect … reducer: (action, state) => switch (action) { | Increment => ReasonReact.Update(state + 1) | Decrement => ReasonReact.Update(state - 1) }
  37. @MoOx 76 REASONREACT: REDUCER COMPONENT Send actions in your render

    function render: ({state, send}) => <div> (ReasonReact.stringToElement(string_of_int(state))) <Button onClick=((_) => send(Increment)) title="+" /> <Button onClick=((_) => send(Decrement)) title="-" /> </div>
  38. @MoOx We all come up with the wrong assumptions on

    our first pass at something 80 SUM UP
  39. @MoOx Fix your assumptions at the type level and let

    the compiler show you the way 81 SUM UP