WELCOME TO

Sébastien Besnier

Fullstack Functional Programming without Monads

@_sebbes_

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
moveTo(150, 50);
circle(50);
// HEAD
moveTo(100, 100);
circle(100);

GOAL

RESULT

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
moveTo(150, 50);
circle(50);
// HEAD
moveTo(100, 100);
circle(100);

GOAL

RESULT

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
setColor("blue");
moveTo(150, 50);
circle(50);
// HEAD
moveTo(100, 100);
circle(100);

ON ACTUAL CODE BASE

50-100 lines

3000 lines

3000 lines

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
setColor("blue");
moveTo(150, 50);
circle(50);
// HEAD
moveTo(100, 100);
circle(100);
setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
setColor("blue");
moveTo(150, 50);
circle(50);
// HEAD
moveTo(50, 50);
circle(100);

We focus on

ON ACTUAL CODE BASE

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
setColor("blue");
moveTo(150, 50);
circle(50);
// HEAD
moveTo(50, 50);
circle(100);

We usually don't look at...

We focus on

ON ACTUAL CODE BASE

RESULT

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
setColor("blue");
moveTo(150, 50);
circle(50);
// HEAD
moveTo(100, 100);
circle(100);

SO THIS HAPPENS
ON ACTUAL CODE BASE

BUG IS EXPENSIVE

User reports bug

BUG IS EXPENSIVE

User reports bug

Product team documents the bug

BUG IS EXPENSIVE

Dev fixes bug

User reports bug

Product team documents the bug

BUG IS EXPENSIVE

Code review

User reports bug

Product team documents the bug

Dev fixes bug

BUG IS EXPENSIVE

Product team checks the bug fix

User reports bug

Product team documents the bug

Dev fixes bug

Code review

BUG IS EXPENSIVE

Product team checks the bug fix

User reports bug

Dev fixes bug

Product team documents the bug

Code review

A lot of
people,
time,
communication
involved

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
moveTo(100, 50);
circle(50);
// HEAD
moveTo(50, 50);
circle(100);

How many input args for circle?

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
moveTo(100, 50);
circle(50);
// HEAD
moveTo(50, 50);
circle(100);

3 input parameters:

* 1 explicit: size (100)

* 2 hidden: position and color

How many input args for circle?

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
moveTo(100, 50);
circle(50);
// HEAD
moveTo(50, 50);
circle(100);

output parameters:

 

3 input parameters:

* 1 explicit: size (100)

* 2 hidden: position and color

How many input args for circle?

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
moveTo(100, 50);
circle(50);
// HEAD
moveTo(50, 50);
circle(100);

output parameters:

* no explicit ones

* 1 hidden: global var mutation

3 input parameters:

* 1 explicit: size (100)

* 2 hidden: position and color

How many input args for circle?

setColor("red");
// LEFT EAR
circle(50);
// RIGHT EAR
moveTo(100, 50);
circle(50);
// HEAD
moveTo(50, 50);
circle(100);

output parameters:

* no explicit ones

* 1 hidden: global var mutation

3 input parameters:

* 1 explicit: size (100)

* 2 hidden: position and color

How many input args for circle?

SIDE EFFECT 
==
HIDDEN PARAMETER

LOCAL CODE CHANGES

⇒ GLOBAL BEHAVIOR CHANGES

LOCAL CODE CHANGES

⇒ GLOBAL BEHAVIOR CHANGES

MAINTENANCE
NIGHTMARE

(PURE) DATA

Describe "WHAT" instead of "HOW"

[
  // LEFT EAR
  { pos: [50, 50], color: "red",
    size: 50, shape: "circle"
  },
  // RIGHT EAR
  { pos: [150, 50], color: "red",
    size: 50, shape: "circle"
  },
  // HEAD
  { pos: [100, 100], color: "red",
    size: 100, shape: "circle"
  }
]
[
  // LEFT EAR
  { pos: [50, 50], color: "red",
    size: 50, shape: "circle"
  },
  // RIGHT EAR
  { pos: [150, 50], color: "red",
    size: 50, shape: "circle"
  },
  // HEAD
  { pos: [100, 100], color: "red",
    size: 100, shape: "circle"
  }
]
[
  // LEFT EAR
  { pos: [50, 50], color: "red",
    size: 50, shape: "circle"
  },
  // RIGHT EAR
  { pos: [150, 50], color: "blue",
    size: 50, shape: "circle"
  },
  // HEAD
  { pos: [100, 100], color: "red",
    size: 100, shape: "circle"
  }
]
[
  // LEFT EAR
  { pos: [50, 50], color: "red",
    size: 50, shape: "circle"
  },
  // RIGHT EAR
  { pos: [150, 50], color: "blue",
    size: 50, shape: "circle"
  },
  // HEAD
  { pos: [100, 100], color: "red",
    size: 100, shape: "circle"
  }
]

This only creates a new value.
NOTHING IS DISPLAYED!

draw([
  // LEFT EAR
  { pos: [50, 50], color: "red",
    size: 50, shape: "circle"
  },
  // RIGHT EAR
  { pos: [150, 50], color: "blue",
    size: 50, shape: "circle"
  },
  // HEAD
  { pos: [100, 100], color: "red",
    size: 100, shape: "circle"
  }
])

Only ONE side effect!

draw([
  // LEFT EAR
  { pos: [50, 50], color: "red",
    size: 50, shape: "circle"
  },
  // RIGHT EAR
  { pos: [150, 50], color: "blue",
    size: 50, shape: "circle"
  },
  // HEAD
  { pos: [100, 100], color: "red",
    size: 100, shape: "circle"
  }
])

Only ONE side effect!

PUSH SIDE EFFECTS ASIDE!

PURE FUNCTIONS

Side Effect Free!

function mickey() {
  return [
    { pos: [50, 50], color: "red",
      size: 50, shape: "circle"
    },
    { pos: [150, 50], color: "blue",
      size: 50, shape: "circle"
    },
    { pos: [100, 100], color: "red",
      size: 100, shape: "circle"
    }
  ];
}

draw(mickey());
function mickey(x, y) {
  return [
    { pos: [x, y], color: "red",
      size: 50, shape: "circle"
    },
    { pos: [x+100, y], color: "blue",
      size: 50, shape: "circle"
    },
    { pos: [x+50, y+50], color: "red",
      size: 100, shape: "circle"
    }
  ];
}

draw(mickey(50, 50));
function mickey(x, y) {
  return [
    { pos: [x, y], color: "red",
      size: 50, shape: "circle"
    },
    { pos: [x+100, y], color: "blue",
      size: 50, shape: "circle"
    },
    { pos: [x+50, y+50], color: "red",
      size: 100, shape: "circle"
    }
  ];
}

draw(mickey(50, 50));

This function doesn't have:

  • hidden input
     
  • hidden output
function mickey(x, y) {
  return [
    { pos: [x, y], color: "red",
      size: 50, shape: "circle"
    },
    { pos: [x+100, y], color: "blue",
      size: 50, shape: "circle"
    },
    { pos: [x+50, y+50], color: "red",
      size: 100, shape: "circle"
    }
  ];
}

draw(mickey(50, 50));

PURE FUNCTION

This function doesn't have:

  • hidden input
     
  • hidden output
function isLightOn() {
  var h = (new Date()).getHours();
  return (h < 7) || (h > 19);
}

function isLightOn() {
  var h = (new Date()).getHours();
  return (h < 7) || (h > 19);
}

IMPURE

Very hard to test!

Results depend on current time

function isLightOn() {
  var h = (new Date()).getHours();
  return (h < 7) || (h > 19);
}



function isLightOn(hours) {
  return (hours < 7) || (hours > 19);
}

IMPURE

Very hard to test!

Results depend on current time

function isLightOn() {
  var h = (new Date()).getHours();
  return (h < 7) || (h > 19);
}



function isLightOn(hours) {
  return (hours < 7) || (hours > 19);
}

IMPURE

PURE

isLightOn(5) == true
isLightOn(10) == false
isLightOn(21) == true

Very hard to test!

Results depend on current time

Easy to test!

Results only depend on input args

Pure Functions are

  • Referentially Transparent
  • Easy to Test
  • Easy to Reason about
function setup(config) { 
  window.url = config.url + "&t=42";
  // ...
}

function build_img() {
  const img = new Image();
  img.src = widow.url;
  return img;
}

setup(config);
// ...
build_img();
function setup(config) { 
  window.url = config.url + "&t=42";
  // ...
}

function build_img() {
  const img = new Image();
  img.src = widow.url;
  return img;
}

setup(config);
// ...
build_img();

IMPURE

???

function enrich_config(config) { 
  return {
    url: config.url + "&t=42",
    // ...
  };
}

function build_img(enriched_config) {
  const img = new Image();
  img.src = enriched_config.url;
  return img;
}

enriched_config = enrich_config(config);
build_img(enriched_config);

PURE

function enrich_config(config) { 
  return {
    url: config.url + "&t=42",
    // ...
  };
}

function build_img(enriched_config) {
  const img = new Image();
  img.src = enriched_config.url;
  return img;
}

enriched_config = enrich_config(config);
build_img(enriched_config);

PURE

PUSH SIDE EFFECTS ASIDE!

Notorious impure functions

  • display on screen
  • user input
  • HTTP (or database) request
  • document.getElementById
  • document.body.clientWidth
  • Math.random()

Notorious impure functions

  • display on screen
  • user input
  • HTTP (or database) request
  • document.getElementById
  • document.body.clientWidth
  • Math.random()
  • launchRocket()

MOVE MICKEY BY CLICKING ON IT

function mickey(x, y) {
  return [
    { pos: [x, y], color: "red",
      size: 50, shape: "circle"
    },
    { pos: [x+100, y], color: "blue",
      size: 50, shape: "circle"
    },
    { pos: [x+50, y+50], color: "red",
      size: 100, shape: "circle"
    }
  ];
}

draw(mickey(50, 50));
function mickey(x, y) {
  return [
    { pos: [x, y], color: "red",
      size: 50, shape: "circle"
    },
    { pos: [x+100, y], color: "blue",
      size: 50, shape: "circle"
    },
    { pos: [x+50, y+50], color: "red",
      size: 100, shape: "circle"
    }
  ];
}

draw(mickey(50, 50));

STATE

var state = { x : 50, y : 50};

var state = { x : 50, y : 50};

function view(state) {
  return mickey(state.x, state.y);
}
var state = { x : 50, y : 50};

function view(state) {
  return mickey(state.x, state.y);
}

PURE FUNCTION

var state = { x : 50, y : 50};

function view(state) {
  return mickey(state.x, state.y);
}
draw(view(state)); // intial rendering

PURE FUNCTION

var state = { x : 50, y : 50};

function view(state) {
  return mickey(state.x, state.y);
}
draw(view(state)); // intial rendering

function handle_event(event) {
  /* ...computing new_state...
   */
  state = new_state;
  draw(view(state));
}

PURE FUNCTION

function handle_event(event) {
  switch(event) {
      case 'leftEarClicked': 
      	var new_state =
            { ...state, 
              x: state.x - 1
            };
        break;
      //...
  }
  state = new_state;
  draw(view(state));
}
function handle_event(event) {
  switch(event) {
      case 'leftEarClicked': 
      	var new_state =
            { ...state, 
              x: state.x - 1
            };
        break;
      //...
  }
  state = new_state;
  draw(view(state));
}

IMPURE

function handle_event(event) {




  const new_state = update(state, event);




  state = new_state;
  draw(view(state));
}

IMPURE

function handle_event(event) {




  const new_state = update(state, event);




  state = new_state;
  draw(view(state));
}

IMPURE

function update(state, event){
  switch(event) {
    case 'leftEarClicked': 
      return {
        ...state, 
        x: state.x - 1
      };
      //...
  }
}
function handle_event(event) {




  const new_state = update(state, event);




  state = new_state;
  draw(view(state));
}

IMPURE

PURE FUNCTION

function update(state, event){
  switch(event) {
    case 'leftEarClicked': 
      return {
        ...state, 
        x: state.x - 1
      };
      //...
  }
}
function handle_event(event) {
  
  
  const new_state = update(state, event);
  
  
  state = new_state;
  draw(view(state));
}
function handle_event(event) {
  
  
  const new_state = update(state, event);
  
  
  state = new_state;
  draw(view(state));
}

FRAMEWORK PROVIDES...

function handle_event(event) {
  
  
  const new_state = update(state, event);
  
  
  state = new_state;
  draw(view(state));
}

PROGRAMMER DEFINES...

FRAMEWORK PROVIDES...

function handle_event(event) {
  
  
  const new_state = update(state, event);
  
  
  state = new_state;
  draw(view(state));
}

PROGRAMMER DEFINES

PURE FUNCTIONS!

FRAMEWORK PROVIDES...

TRIGGER EVENTS

function mickey(x, y) {
  return [
    { pos: [x, y], color: "red",
      size: 50, shape: "circle"
    },
    { pos: [x+100, y], color: "blue",
      size: 50, shape: "circle"
    },
    { pos: [x+50, y+50], color: "red",
      size: 100, shape: "circle"
    }
  ];
}
function mickey(x, y) {
  return [
    { pos: [x, y], color: "red",
      size: 50, shape: "circle",
      onClick: "leftEarClicked"
    },
    { pos: [x+100, y], color: "blue",
      size: 50, shape: "circle",
      onClick: "rightEarClicked"
    },
    { pos: [x+50, y+50], color: "red",
      size: 100, shape: "circle"
    }
  ];
}
function mickey(x, y) {
  return [
    { pos: [x, y], color: "red",
      size: 50, shape: "circle",
      onClick: "leftEarClicked"
    },
    { pos: [x+100, y], color: "blue",
      size: 50, shape: "circle",
      onClick: "rightEarClicked"
    },
    { pos: [x+50, y+50], color: "red",
      size: 100, shape: "circle"
    }
  ];
}

PURE DATA

PURE DATA

function draw(shapes){
  for(const s of shapes){
    // ... draw s...
    
    
    

    
    
    }
  }
}
s = {
    x: 50,
    ...,
    onClick: "leftEarClicked",
}
function draw(shapes){
  for(const s of shapes){
    // ... draw s ...
    if(s.onClick) {
      
      // ...
      // add appropriate event listener
      // ...
      
    }
  }
}
s = {
    x: 50,
    ...,
    onClick: "leftEarClicked",
}
function draw(shapes){
  for(const s of shapes){
    // ... draw s ...
    if(s.onClick) {
      addClickListener(evt => {
        if(/* s is clicked */) {
          handle_event(s.onClick);
        }
      });
    }
  }
}
s = {
    x: 50,
    ...,
    onClick: "leftEarClicked",
}
function handle_event(event) {
  
  
  const new_state = update(state, event);
  
  
  state = new_state;
  draw(view(state));
}

PROGRAMMER DEFINES

PURE FUNCTIONS!

FRAMEWORK PROVIDES...

THE  ELM  ARCHITECTURE

THE  ELM  ARCHITECTURE

Implemented in (or variations):

  • elm (captain obvious!)
  • Vuex (Vue.js)
  • Redux
  • NgRx/NGXS (Angular)

THE  ELM  ARCHITECTURE

INITIAL STATE

TIME

THE  ELM  ARCHITECTURE

Event 1

INITIAL STATE

TIME

THE  ELM  ARCHITECTURE

Event 1

INITIAL STATE

update(event, state)

TIME

THE  ELM  ARCHITECTURE

Event 1

INITIAL STATE

STATE 2

update(event, state)

TIME

THE  ELM  ARCHITECTURE

Event 1

Event 2

INITIAL STATE

STATE 2

STATE 3

update(event, state)
update(event, state)

TIME

THE  ELM  ARCHITECTURE

Event 1

Event 2

Event 3

INITIAL STATE

STATE 2

STATE 3

STATE 4

update(event, state)
update(event, state)
update(event, state)

TIME

THE  ELM  ARCHITECTURE

Event 1

Event 2

Event 3

Event 4

INITIAL STATE

STATE 2

STATE 3

STATE 4

STATE 5

update(event, state)
update(event, state)
update(event, state)
update(event, state)

TIME

TIME  TRAVEL DEBUGGER

  • out of the box in elm      
  • need some install in other frameworks

Hey, Mario!
Demo time!

DATABASE 101

ID NAME IS ADMIN
1 Alice Yes
2 Bob No
3 Charlie No
4 Daine Yes
5 Evan No
6 Flora No

DATABASE 101

ID NAME IS ADMIN
1 Alice Yes
2 Bob No
3 Charlie No
4 Daine Yes
5 Evan No
6 Flora No

Reflects the STATE of the application

Event

TIME

Event

Event

Event

Event

Event

Event

Event

05:11
05:31
05:45
06:42
06:44
07:02
07:13
07:22

Event

05:05

STORE

Event

TIME

Event

User 4 renamed to "Diane"

Event

Event

Event

Event

Event

05:11
05:31
05:45
06:42
06:44
07:02
07:13
07:22

Event

05:05

STORE

Event

TIME

Event

User 4 renamed to "Diane"

Event

Event

Event

Event

Event

05:11
05:31
05:45
06:42
06:44
07:02
07:13
07:22
05:22

Event

05:05

STATE
at 05:22

My trip at Farcheville




By Daine


Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed aliquam, nisl in scelerisque interdum, ipsum ipsum scelerisque purus, at dapibus sapien eros a odio. Vestibulum feugiat vehicula ipsum, eget facilisis felis sodales quis. Maecenas tincid

STORE

Event

TIME

Event

User 4 renamed to "Diane"

Event

Event

Event

Event

Event

05:11
05:31
05:45
06:42
06:44
07:02
07:13
07:22
06:43

Event

05:05

STATE
at 06:43

My trip at Farcheville




By Diane


Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed aliquam, nisl in scelerisque interdum, ipsum ipsum scelerisque purus, at dapibus sapien eros a odio. Vestibulum feugiat vehicula ipsum, eget facilisis felis sodales quis. Maecenas tincid

STORE

Event

TIME

Event

User 4 renamed to "Diane"

Event

User 3 promoted Admin

Post "I like nazis" published

Post 666 removed

Post 418 removed

05:11
05:31
05:45
06:42
06:44
07:02
07:13
07:22

Event

05:05

PWNED

STORE

Event

TIME

Event

User 4 renamed to "Diane"

Event

User 3 promoted Admin

Post "I like nazis" published

Post 666 removed

Post 418 removed

05:11
05:31
05:45
06:42
06:44
07:02
07:13
07:22

Event

05:05

STORE

Event

TIME

Event

User 4 renamed to "Diane"

Event

Box moved 2px to the right (event id: 12345)

Event

Event

Event

05:11
05:31
05:45
06:42

Event

05:05
07:32
07:33
07:34
07:48

STORE

Event

TIME

Event

User 4 renamed to "Diane"

Event

Box moved 2px to the right (event id: 12345)

Event 12345 ignored (event id: 12346)

Event

Event

05:11
05:31
05:45
06:42
07:32
07:33
07:34
07:48

Event

05:05

CTRL+Z

STORE

Event

TIME

Event

User 4 renamed to "Diane"

Event

Box moved 2px to the right (event id: 12345)

Event 12346 ignored

Event

05:11
05:31
05:45
06:42
07:32
07:33
07:34
07:48

Event

05:05

CTRL+Z

CTRL+SHIFT+Z

STORE

Event 12345 ignored (event id: 12346)

Event

TIME

Event

User 4 renamed to "Diane"

Event

Event

Event

Event

Event

STORE

05:11
05:31
05:45
06:42

Event

05:05

EVENT SOURCING

07:32
07:33
07:34
07:48

Event

TIME

Event

User 4 renamed to "Diane"

Event

Event

Event

Event

Event

05:11
05:31
05:45
06:42

Event

05:05

EVENT SOURCING

Constraining side effects!

07:32
07:33
07:34
07:48

STORE

PERFORMANCE

function handle_event(event) {
  
  
  const new_state = update(state, event);
  
  
  state = new_state;
  draw(view(state));
}
function handle_event(event) {
  
  
  const new_state = update(state, event);
  
  
  state = new_state;
  draw(view(state));
}

Redraw the entire screen

var previous_view = view(init_state);
draw(previous_view);

function handle_event(event) {  
  
  const new_state = update(state, event);
  const new_view = view(new_state);
  
  apply_diff(previous_view, new_view);
  state = new_state;
  previous_view = new_view; 
}
var previous_view = view(init_state);
draw(previous_view);

function handle_event(event) {  
  
  const new_state = update(state, event);
  const new_view = view(new_state);
  
  apply_diff(previous_view, new_view);
  state = new_state;
  previous_view = new_view; 
}

CHEAP

CHEAP

MODERATE

COSTLY

Diff on pixels

Our Toy Implementation

Diff on pixels

Our Toy Implementation

Diff on DOM

Elm, React, Vue

Virtual DOM

Map !

fib = [1,1,2,3,5,8,13,21,34,55];
fib.map(n => n + 1);
1
1
2
3
5
8
13
21
34
55
2
2
3
4
6
9
14
22
35
56

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

fib = [1,1,2,3,5,8,13,21,34,55];
fib.map(n => n + 1);
for(var i = 0; i < fib.length; i++) {
  fib[i] = fib[i] + 1;
}
fib = [1,1,2,3,5,8,13,21,34,55];
fib.map(n => n + 1);
for(var i = 0; i < fib.length; i++) {
  fib[i] = fib[i] + 1;
}

WHAT

HOW

fib = [1,1,2,3,5,8,13,21,34,55];
fib.map(n => n + 1);
fib.map(n => print(n));
fib.map(n => print(n));

IMPURE FUNCTION

→ORDER MATTERS

fib.map(n => n + 1);
1
1
2
3
5
8
13
21
34
55
2
2
3
4
6
9
14
22
35
56

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

PURE FUNCTION

fib.map(n => n + 1);

PURE FUNCTION

1
1
2
3
5
8
13
21
34
55
2
2
3
4
6
9
14
22
35
56

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

Alice

Bob

Charlie

Let's explore other languages!

map (\n -> n + 1) fib
1
1
2
3
5
8
13
21
34
55
2
2
3
4
6
9
14
22
35
56

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

CPU 1

CPU 2

CPU 3

HASKELL

"General purpose"
functional programming language

Compilers

multicore compiler

PHP transformer

GraphQL → SQL

Webservers

Servant

Yesod

Others...

  • Finance
  • Security
  • Blockchain
  • ...
map (\n -> n + 1) fib
1
1
2
3
5
8
13
21
34
55
2
2
3
4
6
9
14
22
35
56

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

CORE 1

.
.
.

CORE 1000

SPLIT WORK
ON GPU!

map (\n -> n + 1) fib
1
1
2
3
5
8
13
21
34
55
2
2
3
4
6
9
14
22
35
56

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

SEVER 1

.
.
.

SERVER 100

Pure Functions are

  • Referentially Transparent
  • Easy to Test
  • Easy to Reason about

Pure Functions are

  • Referentially Transparent
  • Easy to Test
  • Easy to Reason about
  • Easy to Parallelize
fib.map(n => n + 1);
for(var i = 0; i < fib.length; i++) {
  fib[i] = fib[i] + 1;
}

Array Reallocated

Array Mutated in place

fib.map(n => n + 1);
for(var i = 0; i < fib.length; i++) {
  fib[i] = fib[i] + 1;
}

Array Reallocated

Array Mutated in place

EFFICIENCY ++

fib.map(n => n + 1);
for(var i = 0; i < fib.length; i++) {
  fib[i] = fib[i] + 1;
}

Array Reallocated

Array Mutated in place

EFFICIENCY ++

BUGS ++

Array Reallocated

Array Mutated in place

EFFICIENCY ++

BUGS --

for(var i = 0; i < fib.length; i++) {
  fib[i] = fib[i] + 1;
}

Uniqueness analysis: if fib isn't used then we can reuse the memory

fib.map(n => n + 1);

FUNCTIONAL PROGRAMMING
without monads!

SIDE EFFECTS

PURE FUNCTIONS

Side Effect Free!

  • Referentially Transparent
  • Easy to Test
  • Easy to Reason about
  • Easy to Parallelize

THE  ELM  ARCHITECTURE

EVENT
SOURCING

OPTIMIZATIONS

HOPE YOU ENJOYED YOUR JOURNEY AT

@_sebbes_

Sébastien Besnier

Fullstack Functional Programming without Monads

By sebbes

Fullstack Functional Programming without Monads

  • 394