 Functional Light JavaScript workshop

Functionite company did an impressive job bringing JavaScript expert Kyle Simpson to their hometown Warsaw, Poland in September last year. He led You Don’t Know JS Workshops, 5 days of JavaScript classes focused on learning new skills and the best practices. I joined on the last day to attend an excellent workshop titled Functional-Light JavaScript. In this post, I wanted to share slides and my coding exercises from this course. If you are curious what topics related to functional programming were covered I strongly recommend checking notes from a similar workshop shared by Beth Allchurch.

Exercise 1

// 1. Make a pure function `bar(..)` to wrap around
// `foo(..)`.

function bar( x, y ) {
let z;

foo( x );
return [ y, z ];

function foo( x ) {
y ++;
z = x * y;
}
}

console.log( bar( 20, 5 ) ); // [ 6, 120 ]
console.log( bar( 25, 6 ) ); // [ 7, 175 ]

// 2. Make a pure function `bar(..)` to wrap around
// `foo(..)`. Use state rollback technique.

function foo( x ) {
y ++;
z = x * y;
}

let y = 5, z;

function barStateRollback( x, yInitial, zInitial ) {
const state = [ y, z ];

[ y, z ] = [ yInitial, zInitial ];

foo( x );

[ yInitial, zInitial ] = [ y, z ];

[ y, z ] = state;

return [ yInitial, zInitial ];
}

console.log( barStateRollback( 20, 5 ) ); // [ 6, 120 ]
console.log( barStateRollback( 25, 6 ) ); // [ 7, 175 ]
console.log( y, z ); // 5, undefined

// 3. Use compose with 3 different functions.

function compose( fn3, fn2, fn1 ) {
return function( input ) {
return fn3( fn2( fn1( input ) ) );
}
}

function add2( x ) {
return x + 2;
}

function double( x ) {
return x * x;
}

function subtract5( x ) {
return x - 5;
}

const doSomeComposeMagic = compose(
);

console.log( doSomeComposeMagic( 6 ) ); // 3
console.log( doSomeComposeMagic( 10 ) ); // 27
console.log( doSomeComposeMagic( 20 ) ); // 227

// 4. Use pipe with the same functions as in (3).

function pipe( fn1, fn2, fn3 ) {
return function( input ) {
return fn3( fn2( fn1( input ) ) );
}
}
const doSomePipeMagic = pipe(
);

console.log( doSomePipeMagic( 6 ) ); // 3
console.log( doSomePipeMagic( 10 ) ); // 27
console.log( doSomePipeMagic( 20 ) ); // 227

Exercise 2

// 1. Define `foo(..)` so that it produces a function
// which remembers only the first two arguments that were
// passed to `foo(..)`, and always adds them together.

function eagerFoo( a, b ) {
const sum = a + b;

return function() {
return sum;
}
}

const x = eagerFoo( 3, 4 );

console.log( x() ); // 7
console.log( x() ); // 7

// 2. The same as (1) but lazy.

function lazyFoo( a, b ) {
let sum;

return function() {
if ( sum === undefined ) {
sum = a + b;
}

return sum;
}
}

const y = lazyFoo( 3, 4 );

console.log( y() ); // 7
console.log( y() ); // 7

Exercise 3

// 1. Turn `mult(..)` into a recursive function that can
// work on as many arguments (2 or more) as necessary.

function mult( result, number, ...numbers ) {
result *= number;
if ( numbers.length === 0 ) {
return result;
}

return mult( result, ...numbers );
}

console.log( mult( 3, 4, 5 ) ); // 60

console.log( mult( 3, 4, 5, 6 ) ); // 360

Exercise 4

// 1. Write two functions, each which return
// a different number value when called.

function foo() {
return 3;
}

function bar() {
return 5;
}

// 2. Write an `add(..)` function that takes two
// numbers and adds them and returns the result. Call
// `add(..)` with the results of your two functions
// from (1) and print the result to the console.

function add( a, b ) {
return a + b;
}

console.log( add( foo(), bar() ) ); // 8

// 3. Write an `add2(..)` that takes two functions
// instead of two numbers, and it calls those two
// functions and then sends those values to `add(..)`,
// just like you did in (2) above.

function add2( fnA, fnB ) {
return fnA() + fnB();
}

console.log( add2( foo, bar ) ); // 8

// 4. Replace your two functions from (1) with a single
// function that takes a value and returns a function
// back, where the returned function will return the
// value when it's called.

function identity( value ) {
return function() {
return value;
}
}

foo = identity( 3 );
bar = identity( 5 );

// 5. Write an `addn(..)` that can take an array of 2
// or more functions, and using only `add2(..)`, adds
// them together. Try it with a loop. Try it without
// a loop (recursion). Try it with built-in array
// functional helpers (map/reduce).

function addnLoop( fns ) {
const length = fns.length;
let result = 0;

for ( let i = 0; i < length; i ++ ) {
identity( result ), fns[ i ]
);
}

return result;
}

console.log(
addnLoop( [ foo, bar, identity( 7 ) ] )
); // 15

function addnRecursion( [ result, fn, ...fns ] ) {
result = add2( result, fn );
if ( fns.length === 0 ) {
return result;
}

[ identity( result ), ...fns ]
);
}

console.log(
addnRecursion( [ foo, bar, identity( 7 ) ] )
); // 15

function addnReduce( fns ) {
return fns.reduce( function( fn0, fn1 ) {
return identity( add2( fn0, fn1 ) );
} )();
}

console.log(
addnReduce( [ foo, bar, identity( 7 ) ] )
); // 15

// 6. Start with an array of odd and even numbers
// (with some duplicates), and trim it down to only
// have unique values.

const input = [ 2, 3, 5, 7, 12, 18, 2, 12, 2 ];

function addUniqueValue( result, value ) {
if ( result.includes( value ) ) {
return result;
}
return result.concat( [ value ] );
}

console.log(
input.reduce( addUniqueValue, [] )
); // [ 2, 3, 5, 7, 12, 18 ]

// 7. Filter your array to only have even numbers in it.

function isEven( value ) {
return value % 2 === 0;
}

console.log(
input.reduce( addUniqueValue, [] )
.filter( isEven )
); // [ 2, 12, 18 ]

// 8. Map your values to functions, using (4), and pass
// the new list of functions to the `addn(..)` from (5).

console.log(
input.reduce( addUniqueValue, [] )
.filter( isEven )
.map( identity )
)
); // 32

All my resources can be found at https://github.com/gziolo/functional-light-js-workshop.

The Economy Of Keystrokes

I also attended JavaScript After Party, a special edition of meet.js Warsaw meetup. I really enjoyed a talk presented by Kyle Simpson The Economy Of Keystrokes. It was both enlightening and entertaining. We often assume that the most important is the speed of writing code. Kyle believes it should be the other way around. We need to focus on the ease of reading instead. He also emphasizes that readability is relative and it highly depends on the familiarity of concepts used in the program.

Warsaw, Poland

I had also a great pleasure to see the surroundings of the National Stadium in Warsaw when visiting this city! 