Introduktion till kombinatorer

Kombinatorer är funktioner på högre nivå som gör att du kan kombinera funktioner, variabler eller andra kombinatorer. Vanligtvis innehåller de inte deklarationer av egna variabler eller affärslogik. De är de enda som kan spola kontrollen i ett funktionsprogram.

I den här artikeln ska jag försöka ta upp några av dem:

Kran

En kombinator är mycket användbar för funktioner som inte returnerar någonting. Den tar den funktion som parametern går till och sedan returneras den.

Förklaring

const tap = (fn) => (värde) => {
fn(värde);
returnerar värde;
};

Imperativt exempel

const [objekt, setItems] = useState(() => [])

axios
.get('http://localhost')
.then({ data } => {
setItems(data)
console.log(data)
onLoadData(data)
}).then(...) // returnerar odefinierat - data i löftet har ändrats

Deklarativt exempel

const [objekt, setItems] = useState(() => [])

axios
.get('http://localhost')
.then(({data }) => data)
.then(tap(setItems)) // (data) => { setItems(data); returnera data }
.then(tap(console.log)) // en då = en funktion = ett ansvar
.then(tap(onLoadData))
.then(...) // fortfarande tillgång till originaldata
// lätt att upprätthålla öppna/stäng-principen

Currying

Den delar upp argumenten i en funktion och gör det möjligt att anropa dem sekventiellt.

Förklaring

const curry = (fn) => {
const curried = (...args) => {
if (fn.length !== args.length){
return curried.bind(null, ...args)
}
return fn(...args);
};

returnera curried

};


Exempel

const curry = (fn) => {
const curried = (...args) => {
if (fn.length !== args.length){
return curried.bind(null, ...args)
}
return fn(...args);
};

returnera curried

};
const sum = (a, b, c) => a + b + c

const currySum = curry(sum)
/*
möjliga anrop
currySum(a)(b)(c),
currySum(a)(b,c),
currySum(a,b)(c),
currySum(a,b,c)
*/

currySum(1) // (b, c) => 1 + a + b eller (b) => (c) => 1 + a + b
currySum(5)(10) // (c) => 5 + 10 + b
currySum(5, 10) // (c) => 5 + 10 + b
currySum(5)(10)(20) // 35
currySum(5, 10)(20) // 35
currySum(5)(10, 20) // 35

const divideBy = curry((a, b) => b / a)
const multiplyBy = curry((a, b) => a * b)

const divideByTwo = divideBy(2)
divideByTwo(10) // returnerar 5

const multiplyByFive = multiplyBy(5)
multiplyByFive(10) // returnerar 50

Rörledning/Compose

Genom komposition är det möjligt att skicka data från en funktion till en annan. Det är viktigt att funktionerna tar samma antal argument. Skillnaden mellan pipe och compose är att den första exekverar funktionen från början till slut, medan compose anropar dem från slutet.

Förklaring

const pipe = (...fns) => (värde, ...args) =>
fns.reduce((v, f, i) =>
i === 0
? f(v, ...args)
: f(v),
värde);

const compose = (...fns) => (värde, ...args) =>
fns.reduceRight((v, f, i) => (v, ... args)
i === (fns.längd - 1)
? f(v, ...args)
: f(v),
värde);
const pipe = (...fns) => (värde, ...args) =>
fns.reduce((v, f, i) =>
i === 0
? f(v, ...args)
: f(v),
värde);

const compose = (...fns) => (värde, ...args) =>
fns.reduceRight((v, f, i) => (v, ... args)
i === (fns.längd - 1)
? f(v, ...args)
: f(v),
värde);

Imperativt exempel

const sinus = (val) => Math.sin(val * Math.PI / 180) // inte läsbar
 sinus(90) // returnerar 1

Deklarativt exempel

const sinus = pipe(
multiplyBy(Math.PI) // ↓ val * Math.PI
divideBy(180), // ↓ val * Math.PI / 180
Math.sin, // ↓ Math.sin(val * Math.PI / 180)
)

const sinus = compose(
Math.sin, // ↑ Math.sin(val * Math.PI / 180)
divideBy(180), // ↑ val * Math.PI / 180
multiplyBy(Math.PI) // ↑ val * Math.PI
)

sinus(90) // returnerar 1

Gaffel

Fork combiner är användbar i situationer där du vill bearbeta ett värde på två sätt och kombinera resultatet.

Förklaring

const fork = (join, fn1, fn2) => (värde) => join(fn1(värde), fn2(värde));

Exempel

const length = (matris) => matris.längd
const sum = (array) => array.reduce((a, b) => a + b, 0)
const divide = (a, b) => a / b

const arithmeticAverage = fork(divide, sum, length)

arithmeticAverage([5, 3, 2, 8, 4, 2]) // returnerar 4

Växling

Denna kombinator tar två funktioner och returnerar resultatet av den första om det är sant. Annars returnerar den resultatet av den andra funktionen.

Förklaring

const alt = (fn, orFn) => (värde) => fn(värde) || orFn(värde)

Exempel

const användare = [{
uuid: '123e4567-e89b-12d3-a456-426655440000',
namn: 'William'
}]

const findUser = ({ uuid: searchesUuid }) => ({ uuid: searchesUuid })
users.find(({ uuid }) => uuid === searchesUuid)

const newUser = data => ({ ...data, uuid: uuid() // skapa ny uuid })

const findOrCreate = alt(findUser, newUser)

findOrCreate({ uuid: '123e4567-e89b-12d3-a456-426655440000' }) // returnerar William-objekt
findOrCreate({ name: 'John' }) // returnerar John-objekt med ny uuid

Sekvens

Den accepterar många oberoende funktioner och skickar samma parameter till var och en av dem. Vanligtvis returnerar dessa funktioner inte något värde.

Förklaring

const seq = (...fns) => (val) => fns.forEach(fn => fn(val))

Exempel

const appendUser = (id) => ({ namn }) => {
document.getElementById(id).innerHTML = namn
}

const printUserContact = pipe(
findOrCreate, // returnerar användare
seq(
appendUser('#contact'), // användare => void
console.log, // användare => void
onContactUpdate // användare => void
)
)

printUserContact(användardata)
samarbetsbanner
sv_SESwedish