Upload
grokking-vn
View
347
Download
1
Embed Size (px)
Citation preview
Maybe Functor in Javascript
Another approach to null handling
1
2
Origin of Null Pointer Exception●Sir Tony Hoare was designing type systems for the
language ALGOL W and he put “Null Pointer Exception” as part of the language, because “because it was so easy to implement”
●In 2009, he called it “The Billion Dollar Mistake”
3
What we want:getCountry('vn').getCity('HCMC').population;
What we have to dovar country = getCountry('vn');if (country !== null) { var city = country.getCity('HCMC');
if (city !== null) {var population = city.population;
}}
How do we fight NULL?
4
Drawbacks:
● Looks complicated
● Error-prone, especially when there are many nesting ifs
● Tedious to write
● Declares a lot of useless variables
●A Functor is a container of a value
Introduction to Functor
5
A value A container of value
● A simple Functor can be implemented through an ES6 classclass Functor { constructor(value) { this.value = value; }}
One important thing about Functor
6
By definition, a functor needs to implement a map function
Remember Array Map?
7
Let’s look at Array’s map function.var addOne = (x) => x + 1;var square = (x) => x * x;
var result = [1, 2, 3].map(addOne) // [2, 3, 4].map(square); // [4, 9, 16]
Implement map for Functor
8
class Functor { constructor(value) { this.value = value; }
map(fn) { var newValue = fn(this.value);
return new Functor(newValue); }}
Let’s see it in action (1)
9
var addOne = (x) => x + 1;var functorOf6 = new Functor(5).map(addOne); // Functor(6)
It can also work with any value, for example, an object:var toUpperCase = (str) => str.toUpperCase();var exciting = (someName) => someName + ’!!!!!!!’;var value = { name: 'grokking' };
var containerOfValue = new Functor(value).map(thing => thing.name) // Functor(‘grokking’)
.map(toUpperCase) // Functor(‘GROKKING’) .map(exciting); // Functor(‘GROKKING!!!!!!!’)
Let’s see it in action (2)
10
Notice that our actual value is still inside the Functor.
var functorOf36 = new Functor(5).map(addOne) // Functor(6)
.map(square); // Functor(36)var result = functorOf36 + 100; // Functor(36) + 100 ???????
How to get the value inside Functor
11
Let’s add another method to Functor to extract the value.class Functor { get() { return this.value; }}
var valueInside = new Functor(5) .map(addOne) // Functor(6) .map(square); // Functor(36) .get(); // 36
var toUpperCase = (str) => str.toUpperCase();var exciting = (someName) => someName + '!!!!!!';var valueInside = new Functor({ name: 'grokking' })
.map(people => people.name) // Functor(‘grokking’) .map(toUpperCase) // Functor(‘GROKKING’) .map(exciting); // Functor(‘GROKKING!!!!!!!’) .get(); // 'GROKKING!!!!!!!'
Now we can get the value inside Functor
12
class Functor { constructor(value) {
this.value = value;}
map(fn) {var newValue = fn(this.value);
return new Maybe(newValue);}
get() {
return this.value; }}
Full implementation of Functor
13
var addOne = (x) => null; // we return Nullvar square = (x) => x * x;
var valueInside = new Functor(1) .map(addOne) // Functor(null) .map(square); // Functor(null * null) ???? .get(); // ????
But we are still affected by NULL
14
The solution is to turn our functor into a Maybe
●Maybe is a kind of Functor that is Null-friendly. Real magic happens in the map function
●Maybe that contains a real value (not null) is usually called a Just / Some
●Maybe that contains null value is usually called a Nothing / None
Introduction to Maybe
15
Maybe(value) = Just(value)Maybe(null) = Nothing
class Maybe { constructor(value) { this.value = value; }
map(fn) {if (this.value !== null) { // Magic happens here
var newValue = fn(this.value); return new Maybe(newValue);
}
return new Maybe(null);}
getOrElse(fallBackValue) {
return (this.value === null) ? this.value : fallBackValue; }}
Let’s implement Maybe
16
It’s pretty much the same as Functor’s example. The only difference is that we use getOrElse instead of get
var addOne = (x) => x + 1;var square = (x) => x * x;
var result = new Maybe(3).map(addOne) // Maybe(4)
.map(square) // Maybe(16) .getOrElse(0); // 16
Maybe in action
17
When Maybe contains NULL, it will not map anymore
var result = new Maybe(3).map(x => null) // Maybe(null)
.map(x => x * x) // Maybe(null) .getOrElse(0); // 0
var result = new Maybe(3).map(x => x + 1) // Maybe(4)
.map(x => null) // Maybe(null) .getOrElse(0); // 0
When Null happens
18
Some real world examples
var family = { grandma: { mother: { you: 'YOUR NAME HERE' } }};
var you = new Maybe(family.grandma) .map(grandma => grandma.mother) .map(mother => mother.you) .getOrElse('DEFAULT NAME');
// returns “YOUR NAME HERE”
var family = { grandma: null};
var you = new Maybe(family.grandma) .map(grandma => grandma.mother) .map(mother => mother.you) .getOrElse('DEFAULT NAME');
// returns “DEFAULT NAME”19
We can use it to safely access nested objects
Compare with what we used to do
20
var you = family.grandma.mother.you || 'DEFAULT NAME';
var you = 'DEFAULT NAME';if (family.grandma &&
family.grandma.mother &&family.grandma.mother.you) { you = family.grandma.mother.you;}
var you = new Maybe(family.grandma) .map(grandma => grandma.mother) .map(mother => mother.you) .getOrElse('DEFAULT NAME');
Short, but unsafe
Safe, but long and nested
Safe and flattened
var population = new Maybe(getCountry('vn')) .map(country => country.getCity('HCMC')) .map(city => city.population) .getOrElse(0);
Some real world examples
var country = getCountry('vn');if (country !== null) { var city = country.getCity('HCMC');
if (city !== null) {var population = city.population;
}}
21
We can rewrite our example earlier
Into shorter and flattened code
●Is just a container of value
●Is a fundamental concept in Functional Programming. From there you can explore Applicative and Monad
●Is a kind of functor that checks null on each map
●Helps flatten your code
●Is used widely in many other languages:
- Haskell, Elm: Maybe
- Java 8/Scala/Rust: Options/Optional
Recap
22
Maybe
Functor
References● https://github.com/fantasyland/fantasy-land Fantasy Land Specification
● https://cwmyers.github.io/monet.js/ Powerful abstractions for Javascript
● http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html Functor, Applicatives, Monads in pictures
● https://en.wikipedia.org/wiki/Functor (looks scary with all the math)
● http://www.mokacoding.com/blog/functor-applicative-monads-in-pictures/ (Maybe in Swift)
● http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html Java 8 Optional
23