Sie sind auf Seite 1von 13

Table of Contents

Introduction 1.1
Everything is Reducible 1.2
Define Composition 1.3
Redefine Map 1.4
Redefine Filter 1.5
Composing Map & Filter 1.6
Transducers 1.7

1
Introduction

Advanced Functional JavaScript


Collection of code snippets to showcase functional aspects of JavaScript

Fun with Functions


1. Everything is Reducible
Reducer Function signature
length of an array
reverse an array
loop thru an array
2. Define Composition
3. Redefine map in different ways
classical map
map as a Reducing Function
map without dependency on input array
map without dependency on array behavior
4. Redefine filter in different ways
classical filter
filter as a Reducing Function
filter without dependency on input array
filter without dependency on array behavior
5. Compose Map & Filter
classical map ⋅ filter combo
map ⋅ filter as a Composable Reducing Function
6. Transducers
recap map & filter w/o dependencies
create mapping & filtering transducers
compose mapping & filtering transducers
use mapping & filtering transducers as Reducing Functions

2
Everything is Reducible

Reducer Function signature

A Reducer Function takes inputs as ( current state , action ) and computes


the next state to return back.

var genericReducerFn = (current_state, input) => next_state;

Example identity reducer shown below returns the same state.

function identity(current_state, action) {


var next_state = current_state;
return next_state;
};
/*---OR---*/

var identity = (current_state, action) => current_state;

Reducer Functions are powerful because they can be passed to a generic


reduce aggregator along with an initial state and a set of actions to
compute the final state

[actions].reduce(reducerFn, initial_state);
//-> final_state

Length of an array

var lengthReducer = (current_length, item) => current_length + 1


;
[4, 3, 2, 1, 0].reduce(lengthReducer, 0);
//-> 5

Reverse an array

3
Everything is Reducible

var arrayPrepender = (current_array, item) => {


var new_array = current_array.slice();
new_array.unshift(item);
return new_array;
};

[1, 2, 3, 4].reduce(arrayPrepender, [ ]);


//-> [4, 3, 2, 1]

Loop thru an array

var looper = (current_state, action) => console.log(action);


[2, 4, 6].reduce(looper, null);
/* 2
* 4
* 6
*/

4
Define Composition

compose(. . .)

compose(h,g,f)(x) = h(g(f(x)))

/**
* usage:
* let inc_one = (x) => x + 1;
* let inc_two = (x) => x + 2;
* let inc_three = compose(inc_one, inc_two);
* inc_three(5); //-> 8
*/
function compose() {
var argsOuter = arguments;
return function() {
var arg = arguments;
var out = undefined;
for(var i = argsOuter.length-1; i >= 0; i--) {
if (out === undefined) {
out = argsOuter[i].apply(null, arg)
} else {
out = argsOuter[i].call(null, out);
}
}
return out;
}
}

let div_by_three = (x) => x/3;


let div_by_five = (x) => x/5;
let div_by_fifteen = compose(div_by_three, div_by_five);
div_by_fifteen(2);
//-> 0.13333333333333333

5
Define Composition

6
Redefine Map

Classical map

[1, 2, 3].map(x => x+1);


//-> [2, 3, 4]

map as a Reducing Function

var map = (fn, arr) => {


return arr.reduce(function(accumulator, input) {
let a = accumulator.slice();
a.push(fn(input));
return a;
}, [ ]);
};

map(x => x+1, [1, 2, 3]);


//-> [2, 3, 4]

Remove map dependency on array input

var map = (fn) => {


return (accumulator, input) => {
let a = accumulator.slice();
a.push(fn(input));
return a;
};
};

[1, 2, 3].reduce(map(x => x+1), [ ]);


//-> [2, 3, 4]

Remove map dependency on accumulator


behavior

7
Redefine Map

var map = (fn) => {


return (reducer) => {
return (accumulator, input) => {
return reducer(accumulator, fn(input));
};
};
};

var arrayConcat = (arr, item) => {


let a = arr.slice();
a.push(item);
return a;
};

[1, 2, 3].reduce(map(x => x+1)(arrayConcat), [ ]);


//-> [2, 3, 4]

8
Redefine Filter

Classical filter

[1, 2, 3, 4].filter(x => x%2 === 0);


//-> [2, 4]

filter as a Reducing Function

var filter = (predicate, arr) => {


return arr.reduce(function(accumulator, input) {
let a = accumulator.slice();
if(predicate(input)) {
a.push(input);
}
return a;
}, [ ]);
};

filter(x => x%2 === 0, [1, 2, 3, 4]);


//-> [2, 4]

Remove filter dependency on array input

var filter = (predicate) => {


return (accumulator, input) => {
let a = accumulator.slice();
if(predicate(input)) {
a.push(input);
}
return a;
};
};

[1, 2, 3, 4].reduce(filter(x => x%2 === 0), [ ]);


//-> [2, 4]

9
Redefine Filter

Remove filter dependency on accumulator


behavior

var filter = (predicate) => {


return (reducer) => {
return (accumulator, input) => {
return predicate(input)?
reducer(accumulator, input):
accumulator;
};
};
};

var arrayConcat = (arr, item) => {


let a = arr.slice();
a.push(item);
return a;
};

[1, 2, 3, 4].reduce(filter(x => x%2 === 0)(arrayConcat), [ ]);


//-> [2, 3, 4]

10
Composing Map & Filter

Classical map & filter

[1, 2, 3, 4].map(x => x+1).filter(x => x<4);


//-> [2, 3]

Compose map & filter using new definitions

var mapFilter = compose(


map(x => x+1),
filter(x => x<4)
);

function arrayConcat(arr, item) {


arr.push(item);
return arr;
};

[1, 2, 3, 4].reduce(mapFilter(arrayConcat), [ ]);


//-> [2, 3]

11
Transducers

Transducers
Mapping & Filtering functions defined with no array behavior dependencies
can be called transducers.

We can easily compose mapping & filtering transducers and use them as
Reducing Functions

Recap map & filter without dependencies

var map = (fn) => {


return (reducer) => {
return (accumulator, input) => {
return reducer(accumulator, fn(input));
};
};
};

var filter = (predicate) => {


return (reducer) => {
return (accumulator, input) => {
return predicate(input)?
reducer(accumulator, input):
accumulator;
};
};
};

Create mapping & filtering transducers

var mappingTransducer = map(x => x+1);


var filteringTransducer = filter(x => x<4);

12
Transducers

Compose mapping & filtering transducers

var mapFilterTransducer = compose(


mappingTransducer,
filteringTransducer
);

Use mapping & filtering transducers

function arrayConcat(arr, item) {


arr.push(item);
return arr;
};

[1, 2, 3, 4].reduce(mapFilterTransducer(arrayConcat), [ ]);


//-> [2, 3]

References
Transducers are coming
CSP and transducers in JavaScript
Transducers.js: A JavaScript Library for Transformation of Data

13

Das könnte Ihnen auch gefallen