Introduksjon til kombinatorer

Kombinatorer er funksjoner på høyere nivå som lar deg kombinere funksjoner, variabler eller andre kombinatorer. Vanligvis inneholder de ikke deklarasjoner av egne variabler eller forretningslogikk. De er de eneste som kan spyle kontrollen i et funksjonsprogram.

I denne artikkelen vil jeg forsøke å ta for meg noen av dem:

Trykk på

En kombinator er veldig nyttig for funksjoner som ikke returnerer noe. Den tar funksjonen som parameteren går til, og deretter returneres den.

Erklæring

const tap = (fn) => (verdi) => {
fn(verdi);
returnere verdi;
};

Imperativt eksempel

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

axios
.get('http://localhost')
.then({ data } => {
setItems(data)
console.log(data)
onLoadData(data)
}).then(...) // returnerer udefinert - dataene i løftet har blitt endret

Deklarativt eksempel

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

axios
.get('http://localhost')
.then(({data }) => data)
.then(tap(setItems)) // (data) => { setItems(data); return data }
.then(tap(console.log))) // en then = en funksjon = et ansvar
.then(tap(onLoadData))
.then(...) // fortsatt tilgang til opprinnelige data
// enkelt å opprettholde åpne/lukke-prinsippet

Currying

Den deler opp argumentene til en funksjon og gjør det mulig å kalle dem sekvensielt.

Erklæring

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

return curried

};


Eksempel

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

return curried

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

const currySum = curry(sum)
/*
mulige 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) // returnerer 5

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

Pipe/Compose

Gjennom komposisjon er det mulig å sende data fra en funksjon til en annen. Det er viktig at funksjonene tar samme antall argumenter. Forskjellen mellom pipe og compose er at den første utfører funksjonen fra først til sist, mens compose kaller dem fra slutten.

Erklæring

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

const compose = (...fns) => (value, ...args) =>
fns.reduceRight((v, f, i) => (v, f, i) => (fns.length)
i === (fns.lengde - 1)
? f(v, ...args)
: f(v),
verdi);
const pipe = (...fns) => (value, ...args) =>
fns.reduce((v, f, i) => (v, f, i)
i === 0
? f(v, ...args)
: f(v),
value);

const compose = (...fns) => (value, ...args) =>
fns.reduceRight((v, f, i) => (v, f, i) => (fns.length)
i === (fns.lengde - 1)
? f(v, ...args)
: f(v),
verdi);

Imperativt eksempel

const sinus = (val) => Math.sin(val * Math.PI / 180) // ikke lesbar
 sine(90) // returnerer 1

Deklarativt eksempel

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) // returnerer 1

Gaffel

Gaffelkombinatoren er nyttig i situasjoner der du ønsker å behandle en verdi på to måter og kombinere resultatet.

Erklæring

const fork = (join, fn1, fn2) => (value) => join(fn1(value), fn2(value));

Eksempel

const length = (matrise) => matrise.lengde
const sum = (matrise) => matrise.reduce((a, b) => a + b, 0)
const divide = (a, b) => a / b

const arithmeticAverage = fork(divide, sum, lengde)

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

Alternasjon

Denne kombinatoren tar to funksjoner og returnerer resultatet av den første hvis det er sant. I motsatt fall returnerer den resultatet av den andre funksjonen.

Erklæring

const alt = (fn, orFn) => (value) => fn(value) || orFn(value)

Eksempel

const users = [{
uuid: '123e4567-e89b-12d3-a456-426655440000',
navn: 'William'
}]

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

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

const findOrCreate = alt(findUser, newUser)

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

Sekvens

Den aksepterer mange uavhengige funksjoner og sender den samme parameteren til hver av dem. Vanligvis returnerer ikke disse funksjonene noen verdi.

Erklæring

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

Eksempel

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

const printUserContact = pipe(
findOrCreate, // returnerer bruker
seq(
appendUser('#contact'), // bruker => void
console.log, // bruker => void
onContactUpdate // bruker => void
)
)

printUserContact(userData)
samarbeidsbanner
nb_NONorwegian