Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

ReasonML: Strict, Powerful, and Forgiving

202 views

Published on

These are the slides for a talk that I gave at JSFoo, Bengaluru, 2018. The complete video for this talk can be viewed at https://youtu.be/3tWExsIae8g

Published in: Technology
  • Be the first to comment

ReasonML: Strict, Powerful, and Forgiving

  1. 1. ReasonML Strict, powerful, and forgiving
  2. 2. Me
  3. 3. After a few months...
  4. 4. Okay, this is like real work now... After a few months...
  5. 5. After a few months...
  6. 6. After a few months...
  7. 7. This looks interesting.
  8. 8. Looks familiar enough...
  9. 9. Oooh. Smart people language.
  10. 10. Buckle… script. Oh, I get it...
  11. 11. It’s so weird. And fascinating!
  12. 12. Go!
  13. 13. That’s it? npm install -g bs-platform npm install -g reason-cli@latest-macos (or linux)
  14. 14. All right then. Let’s code.
  15. 15. Static types? Check! Type inference? Check!
  16. 16. let car = "Blue Maruti 800"; 'use strict'; var car = "Blue Maruti 800"; exports.car = car;
  17. 17. let car = "Blue Maruti 800"; /* This is fine. */ Js.log(car ++ " is sold out"); var car = "Blue Maruti 800"; console.log( "Blue Maruti 800 is sold out" );
  18. 18. let car = "Blue Maruti 800"; /* This is not OK. */ Js.log(car + 1); We've found a bug for you! This has type: string But somewhere wanted: int
  19. 19. let myFirstCar = { colour: "Blue", make: "Maruti", model: "800" }; We've found a bug for you! The record field colour can't be found.
  20. 20. type car = { colour: string, make: string, model: string }; let myFirstCar = { colour: "Blue", make: "Maruti", model: "800" }; var myFirstCar = /* record */[ /* colour */"Blue", /* make */"Maruti", /* model */"800" ];
  21. 21. type colour = Red | Blue | White | Pink;
  22. 22. type colour = Red | Blue | White | Pink; That’s a Variant.
  23. 23. type colour = Red | Blue | White | Pink; These are the variant’s constructors.
  24. 24. type make = Maruti | HindustanMotors; type model = EightHundred | Zen | Ambassador; type colour = Red | Blue | White | Pink; type car = { make: make, model: model, colour: colour }; let myFirstCar = { var myFirstCar = /* colour : Blu /* make : Marut /* model : Eigh ];
  25. 25. make: make, model: model, colour: colour }; let myFirstCar = { make: Maruti, model: EightHundred, colour: Blue }; var myFirstCar = /* colour : Blu /* make : Marut /* model : Eigh ];
  26. 26. ar = { i, tHundred, e var myFirstCar = /* record */[ /* colour : Blue */1, /* make : Maruti */0, /* model : EightHundred */0 ];
  27. 27. model: EightHundred, colour: Blue }; let productionRun = car => { switch (car.model) { | EightHundred => "1983 to 2013" } }; var Caml_builtin_exception require("./stdlib/caml_bui function productionRun(car var match = car[/* model if (match !== 0) { throw [ Caml_builtin_exc /* tuple */[ ".", 19, 2 ] ]; } else { return "1983 to 2013"; } }
  28. 28. d Run = car => { odel) { d => "1983 to 2013" var Caml_builtin_exceptions = require("./stdlib/caml_builtin_exceptions.js"); function productionRun(car) { var match = car[/* model */2]; if (match !== 0) { throw [ Caml_builtin_exceptions.match_failure, /* tuple */[ ".", 19, 2 ] ]; } else { return "1983 to 2013"; } }
  29. 29. make: Maruti, model: EightHundred, colour: Blue }; let productionRun = car => { switch (car.model) { | EightHundred => "1983 to 2013" } }; Warning number 8 You forgot to handle a possible value here, for example: (Zen|Ambassador)
  30. 30. model: EightHundred, colour: Blue }; let productionRun = car => { switch (car.model) { | EightHundred => "1983 to 2013" | Ambassador => "1958 to 2014" | Zen => "1993 to present" } }; function productionRun(car) { var match = car[/* model */2]; switch (match) { case 0 : return "1983 to 2013"; case 1 : return "1993 to present"; case 2 : return "1958 to 2014"; } }
  31. 31. Warning number 8 You forgot to handle a possible value here, for example: (Zen|Ambassador) Use variants to describe possibilities. Got it.
  32. 32. type make = Maruti | HindustanMotors; type model = EightHundred | Zen | Ambassador; type colour = Red | Blue | White | Pink; type car = { make: make, model: model, colour: colour, };
  33. 33. let abomination = { make: HindustanMotors, model: Ambassador, colour: Pink }; var abomination = /* record */[ /* colour : Pink */3, /* make : HindustanMotors */1, /* model : Ambassador */2 ];
  34. 34. /* Nope, not available. */ let pink800 = { make: Maruti, model: EightHundred, colour: Pink }; /* You can buy one of these. */ let pinkZen = { make: Maruti, model: Zen, colour: Pink }; var pink800 = /* record */[ /* colour : Pink */3, /* make : Maruti */0, /* model : EightHundred */0 ]; var pinkZen = /* record */[ /* colour : Pink */3, /* make : Maruti */0, /* model : Zen */1 ];
  35. 35. /* Wut?! */ let marutiAmbassador = { make: Maruti, model: Ambassador, colour: Pink }; var marutiAmbassador = /* record */[ /* colour : Pink */3, /* make : Maruti */0, /* model : Ambassador */2 ];
  36. 36. type car = { make: make, model: model, colour: colour }; /* Wut?! */ let marutiAmbassador = { make: Maruti, var marutiAmbassador = /* record */[ /* colour : Pink */3, /* make : Maruti */0, /* model : Ambassador */2 ];
  37. 37. type ambiColour = JetBlack | OysterBlue | FireBrickRed | EcruBeige; /* and more */ type zenColour = BeamBlue | PearlSilver | BrightRed | FusionPink; /* and more */ type ehColour = BlueBlaze | SilkySilver | BrickRed | SuperiorWhite; /* and more */ type marutiModel = EightHundred(ehColour) | Zen(zenColour); type hmModel = Ambassador(ambiColour); type make = Maruti(marutiModel) | HindustanMotors(hmModel); type car = { make: make };
  38. 38. type ambiColour = JetBlack | OysterBlue | FireBrickRed | EcruBeige; /* and more */ type zenColour = BeamBlue | PearlSilver | BrightRed | FusionPink; /* and more */ type ehColour = BlueBlaze | SilkySilver | BrickRed | SuperiorWhite; /* and more */ type marutiModel = EightHundred(ehColour) | Zen(zenColour); type hmModel = Ambassador(ambiColour); type car = Maruti(marutiModel) | HindustanMotors(hmModel);
  39. 39. let blueMaruti = Maruti(EightHundred(BlueBlaze)); var Block = require("./stdlib/block.js"); var blueMaruti = /* Maruti */Block.__(0, [ /* EightHundred */Block.__(0, [ /* BlueBlaze */0 ]) ]);
  40. 40. let pinkAmbassador = HindustanMotors(Ambassador(FusionPink)); We've found a bug for you! This variant expression is expected to have type ambiColour The constructor FusionPink does not belong to type ambiColour
  41. 41. let marutiAmbassador = Maruti(Ambassador(BlueBlaze)); We've found a bug for you! This variant expression is expected to have type marutiModel The constructor Ambassador does not belong to type marutiModel
  42. 42. Make illegal states unrepresentable.
  43. 43. So, that takes care of data on the inside.
  44. 44. But what about stuff from the outside?
  45. 45. let make = "Maruti"; let model = "Ambassador"; let colour = "FusionPink";
  46. 46. let productionRun = car => { /* Production run as a string. */ }; let inStock = car => { /** * Boolean indicating whether * car model is in stock. */ }
  47. 47. type ambiColour = JetBlack | OysterBlue | FireBrickRed | EcruBeige; /* and more */ type zenColour = BeamBlue | PearlSilver | BrightRed | FusionPink; /* and more */ type ehColour = BlueBlaze | SilkySilver | BrickRed | SuperiorWhite; /* and more */ type marutiModel = EightHundred(ehColour) | Zen(zenColour); type hmModel = Ambassador(ambiColour); type car = Maruti(marutiModel) | HindustanMotors(hmModel);
  48. 48. Maruti Maruti Hindustan Motors 800 Zen Ambassador Jet Black Fusion Pink Blaze Blue
  49. 49. Maruti Ambassador Fusion Pink let make = "Maruti"; let model = "Ambassador"; let colour = "FusionPink";
  50. 50. Where are you going with this?
  51. 51. Where are you going with this? Make illegal states unrepresentable.
  52. 52. Variants Compiler Make illegal states unrepresentable.
  53. 53. Variants Compiler Pattern-matching Functions Make illegal states unrepresentable. Parse all external data & enforce boundaries.
  54. 54. Make illegal states unrepresentable. Parse all external data & enforce boundaries. Mint a module for every type. Enforce invariants using the module interface. Perform compiler-assisted refactoring. Use equational reasoning. Variants Compiler Pattern-matching Functions Modules Abstract types Referential transparency
  55. 55. Variants Compiler Pattern-matching Functions Modules Abstract types Referential transparency Make illegal states unrepresentable. Parse all external data & enforce boundaries. Mint a module for every type. Enforce invariants using the module interface. Perform compiler-assisted refactoring. Use equational reasoning. Patterns! Features!
  56. 56. let f = (~x, ~y=0) => Js.log2(x, y); Warning number 16 This optional parameter in final position will, in practice, not be optional. Reorder the parameters so that at least one non-optional one is in final position or, if all parameters are optional, insert a final (). Explanation: If the final parameter is optional, it'd be unclear whether a function application that omits it should be considered fully applied, or partially applied. Imagine writing `let title = display("hello!")`, only to realize `title` isn't your desired result, but a curried call that takes a final optional argument, e.g. `~showDate`. Formal rule: an optional argument is considered intentionally omitted when the 1st positional (i.e. neither labeled nor optional) argument defined after it is passed in. let x = 1; let y = 2.4; Js.log(x + y); We've found a bug for you! This has type: float But somewhere wanted: int You can convert a float to a int with int_of_float.If this is a literal, you want a number without a trailing dot (e.g. 20). let make = _children => { ...component, initialState: () => { x: "Hello" }, render: self => { { self.state.x |> ReasonReact.string; } } }; We've found a bug for you! Is this a ReasonReact reducerComponent or component with retained props? If so, is the type for state, retained props or action declared _after_ the component declaration? Moving these types above the component declaration should resolve this!
  57. 57. Bye! @harigopal mail@harigopal.in turaku.com discord.gg/reasonml reasonml.chat

×