Johdanto yhdistelmiin

Kombinaattorit ovat korkeamman tason funktioita, joiden avulla voit yhdistää funktioita, muuttujia tai muita kombinaattoreita. Yleensä ne eivät sisällä omien muuttujiensa tai liiketoimintalogiikan julistuksia. Ne ovat ainoat, jotka huuhtelevat ohjausta funktio-ohjelmassa.

Tässä artikkelissa yritän käsitellä muutamia niistä:

Napauta

Kombinaattori on erittäin hyödyllinen funktioissa, jotka eivät palauta mitään. Se ottaa funktion, johon parametri menee, ja sitten se palautetaan.

Ilmoitus

const tap = (fn) => (value) => {
fn(arvo);
return value;
};

Imperatiivinen esimerkki

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

axios
.get('http://localhost')
.then({ data } => {
setItems(data)
console.log(data)
onLoadData(data)
}).then(....) // palaa määrittelemättömänä - lupauksen tietoja on muutettu.

Deklaratiivinen esimerkki

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

axios
.get('http://localhost')
.then(({ data }) => data)
.then(tap(setItems)) // (data) => { setItems(data); return data }
.then(tap(console.log)) // yksi then = yksi funktio = yksi vastuu
.then(tap(onLoadData))
.then(....) // edelleen pääsy alkuperäisiin tietoihin.
// helppo ylläpitää open/close-periaatetta

Currying

Se jakaa funktion argumentit ja mahdollistaa niiden kutsumisen peräkkäin.

Ilmoitus

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

return curried

};


Esimerkki

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)
/*
mahdolliset kutsut
currySum(a)(b)(c),
currySum(a)(b,c),
currySum(a,b)(c),
currySum(a,b,c)
*/

currySum(1) // (b, c) => 1 + a + b tai (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) // palauttaa 5.

const multiplyByFive = multiplyBy(5)
multiplyByFive(10) // palauttaa 50 %.

Putki/sommittele

Komposition avulla on mahdollista siirtää tietoja funktiosta toiseen. On tärkeää, että funktiot ottavat saman määrän argumentteja. Piipun ja koosteen ero on siinä, että ensin mainittu suorittaa funktiot ensimmäisestä viimeiseen, ja kooste kutsuu niitä lopusta alkaen.

Ilmoitus

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

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

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

Imperatiivinen esimerkki

const sine = (val) => Math.sin(val * Math.PI / 180) // ei luettavissa.
 sine(90) // palauttaa 1

Deklaratiivinen esimerkki

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

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

sine(90) // palauttaa 1

Haarukka

Haarukkayhdistelijä on hyödyllinen tilanteissa, joissa haluat käsitellä arvoa kahdella tavalla ja yhdistää tuloksen.

Ilmoitus

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

Esimerkki

const length = (array) => array.length
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]) // palauttaa 4.

Vuorottelu

Tämä yhdistelmä ottaa kaksi funktiota ja palauttaa ensimmäisen tuloksen, jos se on tosi. Muussa tapauksessa se palauttaa toisen funktion tuloksen.

Ilmoitus

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

Esimerkki

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

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

const newUser = data => ({ ...data, uuid: uuid() // luo uusi uuid })

const findOrCreate = alt(findUser, newUser)

findOrCreate({ uuid: '123e4567-e89b-12d3-a456-426655440000' }) // palauttaa William-olion.
findOrCreate({ name: 'John' }) // palauttaa John-olion uudella uuidilla.

Jakso

Se hyväksyy useita itsenäisiä funktioita ja välittää jokaiselle niistä saman parametrin. Tyypillisesti nämä funktiot eivät palauta mitään arvoa.

Ilmoitus

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

Esimerkki

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

const printUserContact = pipe(
findOrCreate, // palauttaa käyttäjän
seq(
appendUser('#contact'), // user => void
console.log, // käyttäjä => void
onContactUpdate // user => void
)
)

printUserContact(userData)
yhteistyöbanneri
fiFinnish