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

ReasonML: A brief introduction

ReasonML: A brief introduction

Brief introduction to Reason from a JavaScript developer perspective and why Reason matters.

Rafa Yepes

June 08, 2017
Tweet

Other Decks in Programming

Transcript

  1. /** * @typedef {Object} ChatMessage * @property {string} msgType -

    Enum('Plain', 'Image', 'Gift') * @property {string} fromUser * @property {string} toUser * @property {string} [text] * @property {string} [src] * @property {string} [giftLabel] */ /** * Send a message to the server * @param {ChatMessage} message */ // … send message to server } function sendMessage(message) {
  2. function sendMessage(message) { if (typeof message.msgType !== 'string') { throw

    new Error('Missing "msgType" property'); } if (typeof message.fromUser !== 'string') { throw new Error('Missing "fromUser" property'); } // … more checks // … send message to server }
  3. OCaml Semantics OCaml Syntax Bytecode Native Reason Syntax BuckleScript JavaScript

    https://spyder.wordpress.com/2017/05/14/ocaml-to-javascript-buzzwords/
  4. • Strong static type system with type inference • Functional

    and immutable by default • ADT and pattern-matching • Very fast • Garbage collected
  5. • Improved syntax • Umbrella project to improve docs and

    tooling • Comes with JSX and React support • A community ASON
  6. LET BINDINGS let message = "hello"; print_endline message; /* Prints

    "hello" */ let message = "bye"; print_endline message; /* Prints "bye" */
  7. BLOCK SCOPE let message = { let part1 = "hello";

    let part2 = "world"; part1 ^ " " ^ part2 }; /* `part1` and `part2` not accessible here! */
  8. CONDITIONALS let message = if (hasName) { let name =

    "Bob"; "Hello " ^ name } else { "Hello!" }; /* `name` not accessible here */
  9. FUNCTIONS /* int => int => int */ let add

    x y => x + y; add 3 2; /* 5 */ /* Functions are curried by default */ let add1 = add 1; add1 2; /* 3 */
  10. LABELED ARGUMENTS let drawCircle ::radius ::color => { setColor color;

    startAt radius radius; /* ... */ }; drawCircle color::"red" radius::10;
  11. RECORDS type person = { name: string, mutable age: int

    }; let me = {name: "Rafa", age: 29}; print_string me.name; me.age = me.age + 1; (* not possible to modify fields unless marked as `mutable` *) me.name = "Bob";
  12. RECORDS type person = { name: string, mutable age: int

    }; let me = {name: "Rafa", age: 29}; print_string me.name; me.age = me.age + 1; (* not possible to modify fields unless marked as `mutable` *) me.name = "Bob"; Error: The record field name is not mutable
  13. PATTERN MATCHING /* int => string */ let intToColorString colorNum

    => { switch colorNum { | 0 => "black" | 1 => "white" }; };
  14. PATTERN MATCHING /* int => string */ let intToColorString colorNum

    => { switch colorNum { | 0 => "black" | 1 => "white" }; }; Warning 8: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: 2
  15. PATTERN MATCHING /* int => string */ let intToColorString colorNum

    => { switch colorNum { | 0 => "black" | 1 => "white" }; };
  16. PATTERN MATCHING /* int => string */ let intToColorString colorNum

    => { switch colorNum { | 0 => "black" | 1 => "white" | _ => "grey" }; };
  17. type basicColor = | Red | Green | Blue; VARIANTS

    & PATTERN MATCHING /* basicColor => int */ let basicColorToInt color => { switch color { | Red => 1 | Green => 2 | Blue => 3 }; };
  18. MODULES module School = { type profession = Teacher |

    Director; let person1 = Teacher; let getProfession person => switch person { | Teacher => "A teacher" | Director => "A director" }; }; let profession = School.getProfession School.person1;
  19. EVERY FILE IS A MODULE /* fileA.re */ /* This

    typically compiles to module FileA below */ let a = 1; let b = 2; /* fileB.re */ /* You can access module FileA from any other module on your system */ let result = FileA.a + FileA.b;
  20. /** * @typedef {Object} ChatMessage * @property {string} msgType -

    Enum('Plain', 'Image', 'Gift') * @property {string} fromUser * @property {string} toUser * @property {string} [text] * @property {string} [src] * @property {string} [giftLabel] */ /** * Sends a message to the server * @param {ChatMessage} message */ // … send message to server } function sendMessage(message) {
  21. type chatMessageType = | Plain | Image | Gift; type

    chatMessage = { msgType: chatMessageType, fromUser: string, toUser: string, text: option string, src: option string, giftLabel: option string };
  22. type chatMessageType = | Plain | Image | Gift; type

    chatMessage = { msgType: chatMessageType, fromUser: string, toUser: string, text: option string, src: option string, giftLabel: option string }; sendMessage({ msgType: Gift, fromUser: "a", toUser: "b", text: None, src: Some “https://url.com/1.jpg", giftLabel: Some "Present for you" });
  23. type chatMessageType = | Plain | Image | Gift; type

    chatMessage = { msgType: chatMessageType, fromUser: string, toUser: string, text: option string, src: option string, giftLabel: option string }; sendMessage({ msgType: Gift, fromUser: "a", toUser: "b", text: None, src: None, giftLabel: None });
  24. type chatMessageType = | Plain | Image | Gift; type

    chatMessage = { msgType: chatMessageType, fromUser: string, toUser: string, text: option string, src: option string, giftLabel: option string }; sendMessage({ msgType: Gift, fromUser: "a", toUser: "b", text: None, src: None, giftLabel: None }); Gift without src should not be valid
  25. type plain = { text: string }; type image =

    { src: string }; type gift = { src: string, giftLabel: option string }; type messageContent = | Plain plain | Image image | Gift gift; type chatMessage = { fromUser: string, toUser: string, content: messageContent };
  26. /* chatMessage => option string */ let getMsgMediaUrl chatMsg =>

    switch chatMsg.content { | Gift {src} => Some src | Image {src} => Some src | _ => None };
  27. /* chatMessage => option string */ let getMsgMediaUrl chatMsg =>

    switch chatMsg.content { | Gift {src} | Image {src} => Some src | _ => None };
  28. /* chatMessage => option string */ let getMsgMediaUrl chatMsg =>

    switch chatMsg.content { | Gift {src} | Image {src} => Some src | Plain _ => None };
  29. /* chatMessage => option string */ let getMsgMediaUrl chatMsg =>

    switch chatMsg.content { | Gift {src} | Image {src} => Some src | Plain _ => None }; /* option string => unit */ let logMsgUrl url => switch url { | Some src => print_endline src | None => () };
  30. /* chatMessage => option string */ let getMsgMediaUrl chatMsg =>

    switch chatMsg.content { | Gift {src} | Image {src} => Some src | Plain _ => None }; /* option string => unit */ let logMsgUrl url => switch url { | Some src => print_endline src | None => () }; let myGift = { fromUser: "a", toUser: "b", content: Gift { src: "https://example.com/123.jpg", giftMsg: Some "Present for you" } }; let messageUrl = getMsgMediaUrl myGift; logMsgUrl messageUrl; /* https://example.com/123.jpg */
  31. /* … */ let getMsgMediaUrl chatMsg => switch chatMsg.content {

    | Gift {src} | Image {src} => Some src | Plain _ => None }; /* … */ type messageContent = | Plain plain | Image image | Gift gift; /* … */
  32. /* … */ type video = { src: string, duration:

    int }; /* … */ let getMsgMediaUrl chatMsg => switch chatMsg.content { | Gift {src} | Image {src} => Some src | Plain _ => None }; /* … */ type messageContent = | Plain plain | Image image | Gift gift;
  33. /* … */ type video = { src: string, duration:

    int }; type messageContent = | Plain plain | Image image | Gift gift | Video video; /* … */ let getMsgMediaUrl chatMsg => switch chatMsg.content { | Gift {src} | Image {src} => Some src | Plain _ => None }; /* … */
  34. /* … */ let getMsgMediaUrl chatMsg => switch chatMsg.content {

    | Gift {src} | Image {src} => Some src | Plain _ => None }; /* … */ /* … */ type video = { src: string, duration: int }; type messageContent = | Plain plain | Image image | Gift gift | Video video; Warning 8: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: Video _
  35. /* … */ type video = { src: string, duration:

    int }; type messageContent = | Plain plain | Image image | Gift gift | Video video; /* … */ let getMsgMediaUrl chatMsg => switch chatMsg.content { | Gift {src} | Image {src} => Some src | Plain _ => None }; /* … */
  36. /* … */ type video = { src: string, duration:

    int }; type messageContent = | Plain plain | Image image | Gift gift | Video video; /* … */ let getMsgMediaUrl chatMsg => switch chatMsg.content { | Gift {src} | Image {src} | Video {src} => Some src | Plain _ => None }; /* … */
  37. WHAT’S NEXT? • More docs • Improve on boarding experience

    • Iterate over Reason-React API • Improve tooling • Just build more apps with Reason!
  38. WHY REASON? • Expressiveness • Easiness to read and understand

    • Correctness • Performance • Refactoring
  39. THE COSTS AND RISKS • “Small” ecosystem • Tooling still

    under heavy development • Not much online material (mostly OCaml) • Requires learning process • No clear module namespace support yet
  40. IS REASON FOR YOU? • Get familiar with the language

    and ecosystem. • Understand the problems you are trying to solve • Understand cost you are going to pay. • Seek support among your team. • Be prepared for the issues you’ll face. • Be responsible. Don’t rewrite. JS interop is #