ํจ์ํ ๊ฐ์ ์น์ 8 ๋ด์ฉ ์ ๋ฆฌ
(๊ฐ์๋ช : ํจ์ํ ํ๋ก๊ทธ๋๋ฐ๊ณผ JavaScript ES6+ ์ ์ธ๋ ๊ฐ์ฌ๋)
Promise๋ Kleisli Composition์ ์ง์ํ๋ ๋๊ตฌ๋ผ๊ณ ๋ณผ ์ ์๋ค.
Kleisli arrow ํจ์ ํฉ์ฑ๋ฐฉ๋ฒ์ ์ค๋ฅ๊ฐ ์์ ์ ์๋ ์ํฉ์์์ ํจ์ ํฉ์ฑ์ ์์ ํ๊ฒ ํ๋ ํ๋์ ๊ท์น์ด๋ค.
์ํ, ํจ๊ณผ, ์ธ๋ถ์ธ์์ ์์กด์ ์ํ ์๊ฐ ์๊ธฐ์ ํจ์ ํฉ์ฑ์ด ์ํ๋๋๋ก ๋์ง์์ ์ ์๋ค.
์๋ฌ๊ฐ ๋ฐ์ํ ์ ์๋ ์ํฉ์ ํด๊ฒฐํ๊ธฐ ์ํ ํจ์ํฉ์ฑ ๋ฐฉ๋ฒ์ด๋ค.
// f . g // f์ g๋ฅผ ํจ์ ํฉ์ฑํ๋ค๊ณ ํ์๋
// ์ ๋ณ์ x๊ฐ ๊ฐ๋ค๋ฉด ๊ฒฐ๊ณผ๊ฐ ๊ฐ๋ค๋ผ๋ ๋ฒ์น
// f(g(x)) = f(g(x)) // x ์ธ์๊ฐ ์ ๋ฌ๋์์๋์ ๊ฒฐ๊ณผ๋ ์ด๋์์ ์ ํ๋๋ผ๋ ํญ์ ๋์ผํด์ผํ๊ธฐ ๋๋ฌธ์ ์ด ์์ด ์ฑ๋ฆฝ๋์ด์ผํจ
ํ์ง๋ง ์ค๋ฌด์์๋ ์ข๋ณ f(g(x))๋ฅผ ํ๊ฐํ ๋ g๊ฐ ๋ฐ๋ผ๋ณด๊ณ ์๋ ๊ฐ์ด ์ฐ๋ณ f(g(x))๋ฅผ ํ๊ฐํ ๋๋ ๋ค๋ฅธ๊ฐ์ผ๋ก ๋ณํด์๋ค๊ฑฐ๋ ๊ฐ์ด ์์ด์ง๊ฑฐ๋ ํ๋ ์ํฉ์ผ๋ก ์ธํด ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์๊ณ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ ๋๋ f(g(x)) = f(g(x))๊ฐ ์ฑ๋ฆฝ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ฌ์ค์ ์์ํ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ํ ์๊ฐ์๋ค.
โ> ๊ทธ๋ฐ ์ํฉ์์๋ ํน์ ํ ๊ท์น์ ๋ง๋ค์ด ํฉ์ฑ์ ์์ ํ๊ฒ ๋ง๋ค๊ณ ์ด๊ฒ์ ์กฐ๊ธ๋ ์ํ์ ์ด๋ผ๊ณ ๋ฐ๋ผ๋ณผ ์ ์๊ฒ ๋ง๋๋ ํจ์ ํฉ์ฑ๋ฒ์ด Kleisli Composition ์ด๋ค.
- Kleisli Composition ๊ท์น - g์์ ์๋ฌ๊ฐ ๋ ๊ฒฝ์ฐ
`f(g(x))` ์ด๋ ๊ฒ ์คํํ์๋ `g(x)`x๋ฅผ g์ ์ ๋ฌํ์๋ ์๋ฌ๊ฐ๋ฐ์ํ๋ฉด f(g(x))์ g(x)์ ๊ฒฐ๊ณผ๊ฐ ๊ฐ๋ค๊ณ ๋ณผ์ ์๋ค.
// f(g(x)) = g(x) // ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋๋ ์์ผ๋ก ํฉ์ฑ๋๋ ๊ฒ์ Kleisli Composition๋ผ๊ณ ํ๋ค.
g์์ ๋ฐ๋ผ๋ณด๋ ๊ฐ์ด ์๋ชป๋๊ฑฐ๋ x์ ์ํ์ ๋ฐ๋ผ ์๋ฌ๊ฐ ๋ฐ์ํ์ ๋ ์ํ์ง์๋ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค๊ฒ ๋๋๋ฐ
g(x)๊ฐ ๋ฆฌํดํ ๊ฐ์ด f(g(x))์ฒ๋ผ f๋ฅผ ํฉ์ฑํ์ง์์๋ ์๋ณ์ด ๋์ผํ ๊ฐ์ด ๋ง๋ค์ด์ง๋ ํฉ์ฑ์ด๋ค.
- ์์
var users = [
{ id: 1, name: 'aa' },
{ id: 2, name: 'bb' },
{ id: 3, name: 'cc' },
];
//์ ์ ๋ฅผ id๊ฐ์ผ๋ก ์ฐพ๋ ํจ์
const getUserById = id => find(u => u.id == id, users);
// name์ ์ถ์ถํ๋ ํจ์
const f = ({name}) => name;
const g = getUserById;
// g๋ฅผ ํตํด ์ํ๋ฅผ ์ฐพ๊ณ ์ฐพ์ ๊ฒฐ๊ณผ์ f๋ฅผ ์ฐ์์ ์ผ๋ก ์คํํด์ ๊ทธ์ฌ๋์ ์ด๋ฆ์ ์ถ์ถํ๋ ํฉ์ฑ์ ํ๊ณ ์ํ๋ค๋ฉด
// ํจ์ํฉ์ฑ์ด ๋ fg๋ ์๋์๊ฐ์ด ๋ง๋ค์ ์๋ค.
const fg = id => f(g(id))
fg(2);// g์์ { id: 2, name: 'bb' },์ด ๊ฐ์ฒด๋ฅผ ์ฐพ์๋ด๊ณ ๊ทธ๋ค์์ f์์ name์ ๊ตฌ์กฐ๋ถํดํ์ฌ ๊บผ๋ด name์ ์ ๋ฌํ๊ฒ๋จ
// 2๋ผ๋ ๊ฐ์ด ์ ์ ๋ฌ๋๋ค๋ฉด ๋ฌธ์ ์์ด ๋์ํ ๊ฒ
log(fg(2));
// ํญ์ ๋์ผํ ๊ฐ์ ์๋ง๋ค ์ ์๋ค๋ ๊ฒ
log(fg(2) == fg(2));
- ์ค๋ฌด์์์ ํ๋ก๊ทธ๋๋ฐ
// ์ค๋ฌด์์๋ users์ ์ํ๊ฐ ๋ณํ๊ธฐ๋ํ๋ค.
// ์๋ฅผ๋ค์ด ์๋์ฒ๋ผ 2๋ฒ์ pop์ด ๋ฐ์ํด์ user์ ์ํ๋ฅผ ๋ณธ๋ค๋ฉด
//users.pop();
//users.pop();
//log(users); // [{id:1, name: 'aa'}] ์ด๋ฐ์์ผ๋ก ์ํ๊ฐ ๋ณํด์๊ณ 2๋ฒ์ ์ ์ ๊ฐ ์ฌ๋ผ์ ธ์์
// ์ ์ ์ํฉ
const result = fg(2);
users.pop();
users.pop();
// ์๋ฌ ๋ฐ์
const result2 = fg(2);
const getUserById = id => find(u => u.id == id, users);
const f = ({name}) => name;
const g = getUserById;
์ ์ฝ๋ ์์ฒด๋ ์์ ํ๊ฒ ์ฝ๋๊ฐ ๋์ํ๋ ํจ์๋ค์ด์ง๋ง ํจ์ ๋๊ฐ(f์ g)๋ฅผ ํฉ์ฑํ ์ํฉ์์
const fg = id => f(g(id))
์ํํ ์ํฉ์ด ์๊ธฐ๊ฒ๋๋ค.
- ์ ์ํํ ์ํฉ์ด ์๊ธฐ๋๊ฐ?
-
f๋ผ๋ ํจ์๋ ํญ์ ๋ฐ๋์ name์ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ์ธ์๋ก ๋ฐ์์ ๋๋ง ์ ์๋์ํ๊ณ ์
-
g๋ผ๋ ํจ์๋ users์์ ๊ฒฐ๊ณผ๊ฐ ์๋ค๊ณ ๊ฐ์ ํ์๋ ์ ์์ ์ผ๋ก ๋์ํ๋ ํจ์๊ฐ๋ฉ๋๋ค
๋ง์ฝ pop์ด ์ผ์ด๋์ง์์๊ณ fg์ users์ ์กด์ฌํ๋ id๋ง ์ ๋ฌ๋๋ค๋ฉด ๋ฌธ์ ์์ด ๋์๋๋๋ฐ pop๊ณผ๊ฐ์ ์ธ๋ถ์ ๋ณํ๊ฐ ์ผ์ด๋๋ค๋ฉด ์ํฉ์ ๋ฐ๋ผ ์๋ฌ๊ฐ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ ํจ์๋ฅผ ํฉ์ฑํ๋ฉด์ ์๋ฌ๊ฐ ๋์ง ์๊ฒ ํ๋๊ฒ์ด Kleisli arrow๋ผ๊ณ ๋ณผ ์ ์๋ค.
const fg = id => Promise.resolve(id).then(g).then(f);
fg(2).then(log); // fg(2) ์คํ๊ฒฐ๊ณผ๋ฅผ log๋ก ์ถ๋ ฅํด๋ณด๊ธฐ // bb
- ์ธ๋ถ์ธ์ ๋ณํ ์ค๋ณด๊ธฐ
users.pop();
users.pop();
fg(2).then(log);// ์๋ฌ๋ฐ์
- ์๋ฌ๋ฐ์๋๋ ์ํฉ์์ Promise๋ ํจ์ ํฉ์ฑ์ ์์ ํ๊ฒ ๋ง๋ค ์ ์๋ค.
// ๊ฒฐ๊ณผ๊ฐ ์์๋ Promise.reject์ด๋ผ๋ ๊ฐ์ ๋ฆฌํดํ๊ฒ ํ๋ค.
const getUserById = id => find(u => u.id == id, users) || Promise.reject('์์!');
users.pop();
users.pop();
g(1) // ์ ์
g(2) // rejected๋ ํ๋ก๋ฏธ์ค ๊ฐ์ ๋ฐ๊ณ ์์
- ๊ฒฐ๊ตญ gํจ์๋
g(2)๋ ์ด๋ค ์ํฉ์์๋ ๋๊ฐ์ g(2)๋ฅผ ํธ์ถํด๋ ์๋ฑํ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค ์ ์๊ฒ ๋ ์ํฉ
์ด๋ ๊ฒ ์ฝ๋ฉํด๋๊ณ ๋์ fg(2).then(log); ๋๊ฐ์ด ์คํํ๋ฉด ์๊น์๋ ๋ค๋ฅด๊ฒ rejected๋ ํ๋ก๋ฏธ์ค๊ฐ ์ถ๋ ฅ๋๊ฒ๋๋ค.
- ๋ง์น ํจ์ ํฉ์ฑ์ด g๋ง ์ผ์ด๋๊ฒ์ฒ๋ผ
fg(2).then(log); ์คํ๊ฒฐ๊ณผ๋ Promise๋ฅผ ๊ทธ๋๋ก ๋ฆฌํดํ๊ณ ํจ์ํฉ์ฑ์ด ๋ง์น g๋ง ์คํํ๊ฒ๊ณผ ๋์ผํ ์ํฉ์ผ๋ก ์ด๋ฃจ์ด์ง๋ค.
- ๋น๊ต
f(g(2)); // undefined๋ผ๋ ์๋ฑํ ๊ฒฐ๊ณผ๊ฐ ๋์ด // ํ๋ก๋ฏธ์ค์ name์ ์ฐพ์ผ๋ undefined
fg(2).then(log);// ์๋ฑํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์๋ค์ด์ง์๊ณ log๋ ์ถ๋ ฅ๋์ง์๋๋ค.
- catch๋ก ์์ ํ๊ฒ!
const fg = id => Promise.resolve(id).then(g).then(f).catch(a => a); // reject๋๋ฉด catch๋ก ์์ ํ๊ฒ ๊ฐ
fg(2).then(log);
g(2)๋ฅผ ์คํํ๋ฉด ์๋ค๋ผ๋ ๊ฐ์ด ๋์ค๊ฒ ๋๊ณ
ํฉ์ฑ๋ ํจ์ fg(2).then(log);๋ฅผ ์คํํ๊ฒ๋๋ฉด โ์์ด์!โ๊ฐ ๋จ์ด์ง๊ฒ๋๋ค.
ํจ์ ํฉ์ฑ ๊ณผ์ ์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค๋ฉด(ex. g์์ ์๋ฌ๋ฐ์) ๋ค์๊ณผ์ ์ ์คํ์ํ๊ณ (ex. f์คํ์ํจ) catch๊ฐ ์คํ๋๊ณ ๊ทธ๋ค์ .then(log)๋ก ํ๋ฌ๊ฐ ์ ์๊ฒ ํด์ค๋ค.
Promise๋ฅผ ํตํด Kleisli ๊ด์ ์ ๋ฐ๋ผ๋ณผ ์ ์๋ค.
- Kleisli ๊ด์
// f(g(x)) = f(g(x))
// f(g(x)) = g(x)