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

Let's create a type system in plain javascript — nCraft 2017

Let's create a type system in plain javascript — nCraft 2017

Arnaud LEMAIRE

May 19, 2017
Tweet

More Decks by Arnaud LEMAIRE

Other Decks in Programming

Transcript

  1. Enables safe composition f g h h = g•f Knowing

    about domain & co-domain leads to a massive advantage
  2. Adapts behavior f { } This is « pattern matching

    » Knowing about domain & co-domain leads to a massive advantage
  3. How do we check types ? const count_word = string

    => { if(typeof string !== 'string') 
 throw new TypeError;
 return string.split(" ").length; }
  4. How do we check types ? const assert = predicate

    => value => { if(!predicate(value)) throw new TypeError; } const count_word = string => { assert(e => typeof e === 'string')(string); return string.split(" ").length; }
  5. How do we check types ? const assert = predicate

    => value => { if(!predicate(value)) throw new TypeError; } const Str = assert(e => typeof e === 'string'); const count_word = string => { Str(string); return string.split(" ").length; }
  6. How can we create a set ? using a constructor

    : - put x in E if x can be a member of E
  7. How do we check types ? const assert = predicate

    => value => { if(!predicate(value)) throw new TypeError; } const Str = value => { assert(e => typeof e === 'string')(value); return value; }; const count_word = 
 string => string.split(" ").length; const typed_count_word = 
 value => count_word(Str(value));
  8. Type refinement const Int = value => { assert(e =>

    e === parseInt(e, 10) && !isNaN(e) )(value); return value; }
  9. Let’s create a type constructor const Type = predicate =>

    value => { assert(predicate)(value); return value; } const Int = Type(
 e => e === parseInt(e, 10) && !isNaN(e)
 );
  10. Type refinement const Int = Type(
 e => e ===

    parseInt(e, 10) && !isNaN(e)
 ); const refinement = (type, predicate) => value =>
 Type(predicate)(type(value)); const PositiveInt = refinement(Int, e => e > 0);
  11. What’s the type ? const count_each_word = string => 


    string.split(" ").reduce( (acc, item) => { acc[item] = (acc[item] || 0) + 1; return acc; } , {});
  12. Type combinator const dict = (domain, codomain) => values =>

    { Object.entries(values)
 .forEach(([key, value]) => { domain(key); codomain(value); }); return values; }; const Phonebook = dict(Str, Int); const phonebook = Phonebook({ 'Andrew Parson': 8806336, 'Emily Everett': 6784346 });
  13. Enums const Vegetable = t.enums.of([ 'Tomato', 'Onion', 'Salad' ], 'Vegetable');

    const Meat = t.enums.of([ 'Mutton' ], 'Meat'); const SeaFood = t.enums.of([ 'Shrimp', 'Fish' ], 'SeaFood');
  14. Struct (& list) const Ingredient = t.union([
 Vegetable, 
 Meat,

    
 SeaFood ], 'Ingredient');
 
 const Kebab = t.struct({ ingredients: t.list(Ingredient), }, 'Kebab');
  15. Typed function const Vegetable = t.enums.of([ 'Tomato', 'Onion', 'Salad' ],

    'Vegetable'); const Kebab = t.struct({ ingredients: t.list(Ingredient), }, 'Kebab'); 
 const isVegetarian = t.func([Kebab], t.Boolean).of(
 ({ingredients}) => ingredients.every(Vegetable.is) ); Type definition Our function
  16. And many other • Dictionary • Tuple • Recursive types

    • Maybe • Intersection • Interface • …
  17. Pattern matching const result = t.match(myCurrentKebab, //do something if the

    kebab is vegetarian VegetarianKebab, (kebab) => ... , //do something else for all other kebab Kebab, (kebab) => ... , //this is definitely not a kebab t.Any, (x) => ... ); The value to match against Type to match Function to execute if the associated type is matched
  18. Take away • Types are not data nor behavior
 they

    can be seen as sets • There is a set algebra we can use to combine types
 (algebraic typing) • Use tComb 
 (we do it, everyday, on all production projets) • And, moreover, it enables a better domain representation