23
Maybe Functor in Javascript Another approach to null handling 1

Grokking TechTalk #16: Maybe functor in javascript

Embed Size (px)

Citation preview

Page 1: Grokking TechTalk #16: Maybe functor in javascript

Maybe Functor in Javascript

Another approach to null handling

1

Page 2: Grokking TechTalk #16: Maybe functor in javascript

2

Page 3: Grokking TechTalk #16: Maybe functor in javascript

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

Page 4: Grokking TechTalk #16: Maybe functor in javascript

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

Page 5: Grokking TechTalk #16: Maybe functor in javascript

●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; }}

Page 6: Grokking TechTalk #16: Maybe functor in javascript

One important thing about Functor

6

By definition, a functor needs to implement a map function

Page 7: Grokking TechTalk #16: Maybe functor in javascript

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]

Page 8: Grokking TechTalk #16: Maybe functor in javascript

Implement map for Functor

8

class Functor { constructor(value) { this.value = value; }

map(fn) { var newValue = fn(this.value);

return new Functor(newValue); }}

Page 9: Grokking TechTalk #16: Maybe functor in javascript

Let’s see it in action (1)

9

var addOne = (x) => x + 1;var functorOf6 = new Functor(5).map(addOne); // Functor(6)

Page 10: Grokking TechTalk #16: Maybe functor in javascript

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

Page 11: Grokking TechTalk #16: Maybe functor in javascript

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; }}

Page 12: Grokking TechTalk #16: Maybe functor in javascript

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

Page 13: Grokking TechTalk #16: Maybe functor in javascript

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

Page 14: Grokking TechTalk #16: Maybe functor in javascript

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

Page 15: Grokking TechTalk #16: Maybe functor in javascript

●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

Page 16: Grokking TechTalk #16: Maybe functor in javascript

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

Page 17: Grokking TechTalk #16: Maybe functor in javascript

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

Page 18: Grokking TechTalk #16: Maybe functor in javascript

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

Page 19: Grokking TechTalk #16: Maybe functor in javascript

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

Page 20: Grokking TechTalk #16: Maybe functor in javascript

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

Page 21: Grokking TechTalk #16: Maybe functor in javascript

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

Page 22: Grokking TechTalk #16: Maybe functor in javascript

●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

Page 23: Grokking TechTalk #16: Maybe functor in javascript

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