Tu código puede ser mejor

y puedo demostrarlo matemáticamente

Motivación


var li = document.getElementsByTagName('li');

var filtered = [];
for (let i = 0; i < li.length; i++) {
    if (li[i].classList.contains('item')) {
        filtered.push(li[i]);
    }
}

for (let i = 0; i < filtered.length; i++) {
    for (let j = 0; j < filtered[i].children.length; j++) {
        let div = document.createElement('div');

        div.classList.add('title');
        div.innerHTML = 'Hello!';
        filtered[i].children[j].insertAdjacentElement('afterbegin', div);
    }
}

                        

$('li')
    .filter('.item')
    .children()
        .prepend(
            $('<div>')
                .addClass('title')
                .html('Hello!')
        );

                        

var filtered = [];
for (let i = 0; i < list.length; i++) {
    if (list[i].age >= 18) {
        filtered.push(list[i]);
    }
}

var sorted = [];
for (let i = 0; i < filtered.length; i++) {
    let max = i;
    for (let j = i; j < filtered.length; j++) {
        if (filtered[j].age > filtered[max].age) {
            max = j;
        }

    }
    sorted[i] = filtered[max];
    filtered[max] = filtered[i];
}

var uppercaseNames = [];
for (let i = 0; i < sorted.length; i++) {
    uppercaseNames[i] = sorted[i].name.toUpperCase();
}

                        

list
    .filter(x => x.age >= 18)
    .sort((a, b) => b.age - a.age)
    .map(x => x.name.toUpperCase());

                        

fs.readFile(path.resolve(__dirname, 'config.json'), function(err, data) {
    if (err) {
        console.log('Something went wrong', err);
        return;
    }

    var config = JSON.parse(data);

    request(config.targetUrl, function(err, response, body) {
        if (err) {
            console.log('Something went wrong', err);
            return;
        }

        fs.writeFile(path.resolve(__dirname, 'target.txt'), body, function(err) {
            if (err) {
                console.log('Something went wrong', err);
                return;
            }

            console.log('Success');
        });
    });
});

                        

fsp.readFile(path.resolve(__dirname, 'config.json'))
    .then(x => JSON.parse(x))
    .then(x => requestp(x.targetUrl))
    .then(x => fsp.writeFile(path.resolve(__dirname, 'target.txt'), x))
    .then(() => console.log('Success') ,(err) => console.log('Something went wrong', err));

                        

Lo básico


function addFourNumbers(a, b, c, d) {
    return a + b + c + d;
}

function addFourNumbersOneByOne(a) {
    return function(b) {
        return function(c) {
            return function(d) {
                return addFourNumbers(a, b, c, d);
            }
        }
    }
}

var addFourNumbersOneByOneᐟ = a => b => c => d => addFourNumbers(a, b, c, d);
                        

var addSix = addFourNumbersOneByOne(1)(2)(3);

addSix(10);
16
                        

var z = g(f(x));
                        

var y = a(b(c(d(e(f(g(h(i(j(k(x)))))))))));

var F = compose(a, b, c, d, e, f, g, h, i, j, k);

var yᐟ = F(x);
                        

Tipos


var num = 12.3; // Number

var str = 'meetup.js'; // String

var bool = true; // Boolean = True | False

var arr = [] // Array
             // Array[a]
             // [a]

var strArr = ['hello', 'world', '!'] // Array[String]

var fn = function() {}; // Function
                        

var fn = function() {}; // Function

// add :: (Number, Number) -> Number
var add = (x,y) => x + y;

//  addᐟ :: Number -> Number -> Number
//  addᐟ :: Number -> (Number -> Number)
var addᐟ = x => y => x + y;

                        

// addTwo :: Number -> Number
var addTwo = x => x + 2;

addTwo(3);
5

addTwo('hello');
"hello2"

addTwo([]);
"2"

addTwo({});
"[object Object]2"

addTwo(undefined);
NaN
                        

// filter :: Function -> Array -> Array
// filter :: (a -> Boolean) -> [a] -> [a]
var filter = pr => xs => xs.filter(pr);

// reduce :: (b -> a -> b) -> b -> [a] -> b
var reduce = fn => acc => xs => xs.reduce(fn, acc);

                        

$ ghci
GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help
Prelude> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
Prelude>
                        

// reduce :: (b -> a -> b) -> b -> [a] -> b
var reduce = fn => acc => xs => xs.reduce(fn, acc);
                        

Entornos


function Environment(something) {
    this.__value = something;
}

var env = new Environment('Help me, I`m trapped inside an environment!');
                        

var Ⅰ_Ⅹ = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
                        

Caso 1


// addTwo :: Number -> Number
var addTwo = x => x + 2;

// [Number]
var Ⅰ_Ⅹ = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// addTwoᐟ :: [Number] -> [Number]
// addTwoᐟ = ಠ_ಠ(addTwo)

// ಠ_ಠ :: (Number -> Number) -> ([Number] -> [Number])

                        

// addTwo :: Number -> Number
var addTwo = x => x + 2;

// [Number]
var Ⅰ_Ⅹ = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// ಠ_ಠ :: (Number -> Number) -> ([Number] -> [Number])
var ಠ_ಠ = function(fn) {
    return function(xs) {
        return xs.map(fn);
    }
};

// addTwoᐟ :: [Number] -> [Number]
addTwoᐟ = ಠ_ಠ(addTwo);

addTwoᐟ(Ⅰ_Ⅹ);
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

// fmap :: (Number -> Number) -> ([Number] -> [Number])
var fmap = ಠ_ಠ;
                        

// addTwo :: Number -> Number
var addTwo = x => x + 2;

// timesThree :: Number -> Number
var timesThree = x => x * 3;

// addTwoᐟ :: [Number] -> [Number]
var addTwoᐟ = fmap(addTwo);

// timesThreeᐟ :: [Number] -> [Number]
var timesThreeᐟ = fmap(timesThree);

// doALotOfThingsᐟ :: [Number] -> [Number]
var doALotOfThingsᐟ = compose(addTwoᐟ, timesThreeᐟ, timesThreeᐟ, addTwoᐟ, timesThreeᐟ);

doALotOfThingsᐟ(Ⅰ_Ⅹ);
[47, 74, 101, 128, 155, 182, 209, 236, 263, 290]
                        

Caso 2


// doALotOfThingsᐟ :: [Number] -> [Number]
var doALotOfThingsᐟ = compose(addTwoᐟ, timesThreeᐟ, timesThreeᐟ, addTwoᐟ, timesThreeᐟ);

// Number
var two = 2;

// ಠ_ಠ :: Number -> [Number]
var ಠ_ಠ = x => [x];

doALotOfThingsᐟ(ಠ_ಠ(two));
74

// unit :: Number -> [Number]
var unit = ಠ_ಠ;
// ʀeturn :: Number -> [Number]
var ʀeturn = ಠ_ಠ;
                        

// sumArray :: [Number] -> Number
var sumArray = reduce((acc, x) => acc + x)(0);

// sumArrayᐟ :: [Number] -> [Number]
var sumArrayᐟ = compose(unit, sumArray);

// lift :: ([Number] -> Number) -> ([Number] -> [Number])
var lift = fn => compose(unit, fn);

var sumArrayᐟ = lift(sumArray);

// doALotOfThingsMoreᐟ :: [Number] -> [Number]
var doALotOfThingsMoreᐟ = compose(doALotOfThingsᐟ, sumArrayᐟ);

doALotOfThingsMoreᐟ(Ⅰ_Ⅹ);
[1505]
                        

Caso 3


// firstFiveMultiplesOf :: Number -> [Number]
var firstFiveMultiplesOf = x => [1, 2, 3, 4, 5].map(n => x * n);

// [Number]
var Ⅰ_Ⅹ = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// firstFiveMultiplesOfᐟ :: [Number] -> [[Number]]
var firstFiveMultiplesOfᐟ = fmap(firstFiveMultiplesOf)

firstFiveMultiplesOfᐟ(Ⅰ_Ⅹ);
[[1, 2, 3, 4, 5], [2, 4, 6, 8, 10], [3, 6, 9, 12, 15], [4, 8, 12, 16, 20], [5, 10, 15, 20, 25], [6, 12, 18, 24, 30], [7, 14, 21, 28, 35], [8, 16, 24, 32, 40], [9, 18, 27, 36, 45], [10, 20, 30, 40, 50]]
                        

// firstFiveMultiplesOf :: Number -> [Number]
var firstFiveMultiplesOf = firstNthMultiplesOf(5);

// [Number]
var Ⅰ_Ⅹ = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// firstFiveMultiplesOfᐟ :: [Number] -> [[Number]]
var firstFiveMultiplesOfᐟ = fmap(firstFiveMultiplesOf)

// ಠ_ಠ :: [[Number]] -> [Number]
var ಠ_ಠ = xss => xss.reduce((acc, xs) => acc.concat(xs), []);

ಠ_ಠ(firstFiveMultiplesOfᐟ(Ⅰ_Ⅹ));
[1, 2, 3, 4, 5, 2, 4, 6, 8, 10, 3, 6, 9, 12, 15, 4, 8, 12, 16, 20, 5, 10, 15, 20, 25, 6, 12, 18, 24, 30, 7, 14, 21, 28, 35, 8, 16, 24, 32, 40, 9, 18, 27, 36, 45, 10, 20, 30, 40, 50]

// join :: [[Number]] -> [Number]
var join = ಠ_ಠ;
// flatten :: [[Number]] -> [Number]
var flatten = ಠ_ಠ;
                        

// firstFiveMultiplesOf :: Number -> [Number]
// fmap firstFiveMultiplesOf :: [Number] -> [[Number]]
// join (fmap firstFiveMultiplesOf) :: [Number] -> [Number]

// chain :: (Number -> [Number]) -> ([Number] -> [Number])
var chain = fn => compose(join, fmap)(fn);

chain(firstFiveMultiplesOf)(Ⅰ_Ⅹ);
[1, 2, 3, 4, 5, 2, 4, 6, 8, 10, 3, 6, 9, 12, 15, 4, 8, 12, 16, 20, 5, 10, 15, 20, 25, 6, 12, 18, 24, 30, 7, 14, 21, 28, 35, 8, 16, 24, 32, 40, 9, 18, 27, 36, 45, 10, 20, 30, 40, 50]
                        

// fmap :: (Number -> Number) -> ([Number] -> [Number])
var fmap = fn => xs => xs.map(fn);

// unit :: Number -> [Number]
var unit = x => [x];

// lift :: ([Number] -> Number) -> ([Number] -> [Number])
var lift = fn => compose(unit, fn);

// join :: [[Number]] -> [Number]
var join = xss => xss.reduce((acc, xs) => acc.concat(xs), []);

// chain :: (Number -> [Number]) -> ([Number] -> [Number])
var chain = fn => compose(join, fmap(fn));
                        

Lazy Promises


2+2;
4

var four = 2 + 2;

four;
4

var four = function() {
    return 2 + 2;
};

four();
4

function thunk() {
    return new Promise((res, rej) => setTimeout(() => res(100), 3000));
}

thunk().then(value => console.log('resolved A', value));
"resolved A" 300

thunk().then(value => console.log('resolved B', value));
"resolved B" 300
                        

// Lazy[a -> Promise[b, x]]
function Lazy(fn) { this.__value = fn; };

// unit :: (a -> Promise[b, x]) -> Lazy[a -> Promise[b, x]]
Lazy.of = fn => new Lazy(fn);

// map :: Lazy[a -> Promise[b, x]] -> (b -> c) -> Lazy[a -> Promise[c, x]]
// map :: Lazy[a -> Promise[b, x]] -> (b -> Promise[c, y]) -> Lazy[a -> Promise[c, y]]
Lazy.prototype.map = function(fn) {
    return Lazy.of((a) => this.__value(a).then(fn));
};

// do :: Lazy[a -> Promise[b, z]] -> a -> Promise[b, z]
Lazy.prototype.do = function(a) {
    return this.__value(a);
};

                        

// thunk :: Number -> Promise[Number, a]
function thunk(n) {
    return new Promise((res, rej) => setTimeout(() => res(100 * n), 1500 * n));
};

// addFifty :: Number -> Number
var addFifty = x => x + 50;

// timesTwoDelayed :: Number -> Promise[Number, a]
var timesTwoDelayed = x => new Promise((res, rej) => setTimeout(() => res(x * 2), 1000));

var lazy = Lazy.of(thunk).map(addFifty).map(timesTwoDelayed);

lazy.do(1).then(value => console.log('resolved A', value));
"resolved A" 300
lazy.do(2).then(value => console.log('resolved B', value));
"resolved B" 500
lazy.do(3).then(value => console.log('resolved C', value));
"resolved C" 700
                        

Control de flujo


// Either[a, b] = Left[a] ㅣ Right[b]

function Either(x) { this.__value = x; };

function Left(...args) { Either.call(this, ...args); };
Left.prototype = Object.create(Either.prototype);

function Right(...args) { Either.call(this, ...args); };
Right.prototype = Object.create(Either.prototype);

// ʟeft :: a -> Left[a]
Left.of = x => new Left(x);
// ʀight :: b -> Right[b]
Right.of = x => new Right(x);

// map :: Either[x, a] -> (a -> b) -> Either[x, b]
Either.prototype.map = function(fn) {
    if (this instanceof Right)
        return Right.of(fn(this.__value));
    else
        return this;
};

                        

// plusOne :: Number -> Number
var plusOne = x => x + 1

// timesTwo :: Number -> Number
var timesTwo = x => x * 2

// toString :: Number -> String
var toString = x => x.toString();

Right.of(1).map(plusOne).map(timesTwo).map(toString);
Right {__value: "4"}
                        

// divideTwoBy :: Number -> Either[String, Number]
var divideTwoBy = function(x) {
    if (x === 0) return Left.of("can't divide by zero");
    else return Right.of(2 / x);
};

// subtractOne :: Number -> Number
var subtractOne = x => x - 1

Right.of(1).map(subtractOne).map(divideTwoBy);
Right {__value: Left {__value: "can't divide by zero"}}
                        

// join :: Either[y, Either[x, a]] -> Either[x, a]
Either.prototype.join = function() {
    return this.__value;
};

// addTen :: Number -> Number
var addTen = x => x + 10;

Right.of(1).map(subtractTwo).map(divideTwoBy).join()
    .map(addTen).map(toString);
Right {__value: "8"}

Right.of(1).map(subtractOne).map(divideTwoBy).join()
    .map(addTen).map(toString);
Left {__value: "can't divide by zero"}
                        

// chain :: Either[x, a] -> (a -> Either[y, b]) -> Either[y, b]
Either.prototype.chain = function(fn) {
    return this.map(fn).join();
};

// unit :: b -> Right[b]
Either.of = x => new Right(x);

Either.of(1).map(subtractTwo).chain(divideTwoBy).map(addTen)
    .map(toString);
Right {__value: "8"}

Either.of(1).map(subtractOne).chain(divideTwoBy).map(addTen)
    .map(toString);
Left {__value: "can't divide by zero"}
                        

// do :: Either[a, b] -> (a -> x) -> (b -> x) -> x
Either.prototype.do = function(l, r) {
    if (this instanceof Right)
        return r(this.__value);
    else
        return l(this.__value);
};

var a = Either.of(1).map(subtractOne).chain(divideTwoBy).map(addTen)
    .map(toString);
var b = Either.of(1).map(subtractTwo).chain(divideTwoBy).map(addTen)
    .map(toString);

a.do(value => console.log('this is a left!', value), value => console.log('this is a right!', value));
"this is a left!" "can't divide by zero"

b.do(value => console.log('this is a left!', value), value => console.log('this is a right!', value));
"this is a right!" "8"
                        

Teoría de categorías

Categorías
Functores
Mónadas

Tu código puede ser mejor

y puedo demostrarlo matemáticamente


fmap(compose(g, f))
                        

compose(fmap(g), fmap(f))
                        

// firstNthNaturals :: Number -> [Number]
var firstNthNaturals = n => Array(n).fill().map((_, idx) => idx + 1);

// [Number]
var Ⅰ_ⅯⅯ = firstNthNaturals(1000000); // [1, 2, ... , 999999, 1000000]

// addTwo :: Number -> Number
var addTwo = x => x + 2;

// timesThree :: Number -> Number
var timesThree = x => x * 3;
                        

var t0 = performance.now();
compose(fmap(addTwo), fmap(timesThree))(Ⅰ_ⅯⅯ);
var t1 = performance.now();

var t2 = performance.now();
fmap(compose(addTwo, timesThree))(Ⅰ_ⅯⅯ);
var t3 = performance.now();

console.log('compose(fmap(g), fmap(f))', t1 - t0, 'ms');
"compose(fmap(g), fmap(f))" 225.44499999999994 "ms"

console.log('fmap(compose(g, f))', t3 - t2, 'ms');
"fmap(compose(g,f))" 134.97500000000002 "ms"
                        

Preguntas?

Gracias!

https://en.wikipedia.org/wiki/Category_(mathematics)
https://en.wikipedia.org/wiki/F-algebra
https://en.wikipedia.org/wiki/Monad_(category_theory)
https://en.wikipedia.org/wiki/Curry
https://wiki.haskell.org/Haskell_Brooks_Curry
https://en.wikipedia.org/wiki/Category_theory
http://interfaithspirit.org/wp-content/uploads/2015/09/metaphysics.jpg
http://img.pandawhale.com/post-38723-Neo-I-know-kung-fu-gif-Imgur-bUjp.gif
https://www.youtube.com/watch?v=g9xDhAKNcHs
wat
http://yannesposito.com/Scratch/en/blog/Category-Theory-Presentation/
https://en.wikibooks.org/wiki/Haskell/Category_theory
https://giphy.com/gifs/excited-birthday-yeah-yoJC2GnSClbPOkV0eA
This slide intentionally left blank