ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ํต์ฌ ๊ฐ๋ ์ธ ํํฐ์ ๋ชจ๋๋๋ฅผ ํ์ํฉ๋๋ค. ์ด ๊ฐ์ด๋๋ ๋ชจ๋ ์์ค์ ๊ฐ๋ฐ์๋ฅผ ์ํด ๋ช ํํ ์ค๋ช ๊ณผ ์ค์ฉ์ ์ธ ์์ , ์ค์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ ๊ณตํฉ๋๋ค.
ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ํํค์น๊ธฐ: ๋ชจ๋๋์ ํํฐ๋ฅผ ์ํ ์ค์ฉ ๊ฐ์ด๋
ํจ์ํ ํ๋ก๊ทธ๋๋ฐ(FP)์ ์ต๊ทผ ๋ช ๋ ๋์ ์๋นํ ์ฃผ๋ชฉ์ ๋ฐ์ผ๋ฉฐ ์ฝ๋ ์ ์ง๋ณด์์ฑ, ํ ์คํธ ์ฉ์ด์ฑ, ๋์์ฑ ๊ฐ์ ๊ณผ ๊ฐ์ ๊ฐ๋ ฅํ ์ด์ ์ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฌ๋ ํํฐ(Functors)์ ๋ชจ๋๋(Monads)์ ๊ฐ์ FP ๋ด์ ํน์ ๊ฐ๋ ๋ค์ ์ฒ์์๋ ์ด๋ ต๊ฒ ๋๊ปด์ง ์ ์์ต๋๋ค. ์ด ๊ฐ์ด๋๋ ์ด๋ฌํ ๊ฐ๋ ๋ค์ ๋ช ํํ ์ค๋ช ํ๊ณ , ์ค์ฉ์ ์ธ ์์ ์ ์ค์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ ๊ณตํ์ฌ ๋ชจ๋ ์์ค์ ๊ฐ๋ฐ์๋ค์๊ฒ ํ์ ์ค์ด์ฃผ๊ณ ์ ํฉ๋๋ค.
ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ด๋?
ํํฐ์ ๋ชจ๋๋์ ๋ํด ์์๋ณด๊ธฐ ์ ์, ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ํต์ฌ ์์น์ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค:
- ์์ ํจ์: ๋์ผํ ์ ๋ ฅ์ ๋ํด ํญ์ ๋์ผํ ์ถ๋ ฅ์ ๋ฐํํ๊ณ ๋ถ์ ํจ๊ณผ(side effects)๊ฐ ์๋(์ฆ, ์ธ๋ถ ์ํ๋ฅผ ์์ ํ์ง ์๋) ํจ์์ ๋๋ค.
- ๋ถ๋ณ์ฑ: ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ๋ถ๋ณ์ด๋ฉฐ, ์์ฑ๋ ํ์๋ ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์์์ ์๋ฏธํฉ๋๋ค.
- ์ผ๊ธ ํจ์: ํจ์๋ ๊ฐ์ผ๋ก ์ทจ๊ธ๋ ์ ์์ผ๋ฉฐ, ๋ค๋ฅธ ํจ์์ ์ธ์๋ก ์ ๋ฌ๋๊ฑฐ๋ ๊ฒฐ๊ณผ๋ก ๋ฐํ๋ ์ ์์ต๋๋ค.
- ๊ณ ์ฐจ ํจ์: ๋ค๋ฅธ ํจ์๋ฅผ ์ธ์๋ก ๋ฐ๊ฑฐ๋ ๊ฒฐ๊ณผ๋ก ๋ฐํํ๋ ํจ์์ ๋๋ค.
- ์ ์ธํ ํ๋ก๊ทธ๋๋ฐ: *์ด๋ป๊ฒ* ๋ฌ์ฑํ ๊ฒ์ธ๊ฐ๋ณด๋ค๋ *๋ฌด์์* ๋ฌ์ฑํ๊ณ ์ถ์์ง์ ์ด์ ์ ๋ง์ถฅ๋๋ค.
์ด๋ฌํ ์์น๋ค์ ์ถ๋ก ํ๊ณ , ํ ์คํธํ๊ณ , ๋ณ๋ ฌํํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์์ฑํ๋๋ก ๋์ต๋๋ค. ํ์ค์ผ(Haskell)์ด๋ ์ค์นผ๋ผ(Scala)์ ๊ฐ์ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ ์ด๋ฌํ ์์น์ ๊ฐ์ ํ๋ ๋ฐ๋ฉด, ์๋ฐ์คํฌ๋ฆฝํธ(JavaScript)๋ ํ์ด์ฌ(Python)๊ณผ ๊ฐ์ ์ธ์ด๋ค์ ๋ณด๋ค ํ์ด๋ธ๋ฆฌ๋์ ์ธ ์ ๊ทผ์ ํ์ฉํฉ๋๋ค.
ํํฐ: ์ปจํ ์คํธ ์์์ ๋งคํํ๊ธฐ
ํํฐ(Functor)๋ map ์ฐ์ฐ์ ์ง์ํ๋ ํ์
์
๋๋ค. map ์ฐ์ฐ์ ํํฐ์ ๊ตฌ์กฐ๋ ์ปจํ
์คํธ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ํํฐ *๋ด๋ถ*์ ๊ฐ(๋ค)์ ํจ์๋ฅผ ์ ์ฉํฉ๋๋ค. ๊ฐ์ ๋ด๊ณ ์๋ ์ปจํ
์ด๋๊ฐ ์๊ณ , ๊ทธ ์ปจํ
์ด๋ ์์ฒด๋ ๊ฑด๋๋ฆฌ์ง ์๊ณ ๋ด๋ถ ๊ฐ์ ํจ์๋ฅผ ์ ์ฉํ๊ณ ์ถ๋ค๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค.
ํํฐ ์ ์ํ๊ธฐ
๊ณต์์ ์ผ๋ก, ํํฐ๋ ๋ค์ ์๊ทธ๋์ฒ๋ฅผ ๊ฐ์ง map ํจ์(ํ์ค์ผ์์๋ ์ข
์ข
fmap์ผ๋ก ๋ถ๋ฆผ)๋ฅผ ๊ตฌํํ๋ ํ์
F์
๋๋ค:
map :: (a -> b) -> F a -> F b
์ด๋ map์ด ํ์
a์ ๊ฐ์ ํ์
b์ ๊ฐ์ผ๋ก ๋ณํํ๋ ํจ์์, ํ์
a์ ๊ฐ์ ํฌํจํ๋ ํํฐ(F a)๋ฅผ ๋ฐ์, ํ์
b์ ๊ฐ์ ํฌํจํ๋ ํํฐ(F b)๋ฅผ ๋ฐํํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
ํํฐ์ ์์
1. ๋ฆฌ์คํธ (๋ฐฐ์ด)
๋ฆฌ์คํธ๋ ํํฐ์ ํํ ์์
๋๋ค. ๋ฆฌ์คํธ์ ๋ํ map ์ฐ์ฐ์ ๋ฆฌ์คํธ์ ๊ฐ ์์์ ํจ์๋ฅผ ์ ์ฉํ์ฌ, ๋ณํ๋ ์์๋ค๋ก ์ด๋ฃจ์ด์ง ์๋ก์ด ๋ฆฌ์คํธ๋ฅผ ๋ฐํํฉ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ์์ :
const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map(x => x * x); // [1, 4, 9, 16, 25]
์ด ์์ ์์ map ํจ์๋ ์ ๊ณฑ ํจ์(x => x * x)๋ฅผ numbers ๋ฐฐ์ด์ ๊ฐ ์ซ์์ ์ ์ฉํ์ฌ, ์๋ณธ ์ซ์์ ์ ๊ณฑ์ ํฌํจํ๋ ์๋ก์ด ๋ฐฐ์ด squaredNumbers๋ฅผ ์์ฑํฉ๋๋ค. ์๋ณธ ๋ฐฐ์ด์ ์์ ๋์ง ์์ต๋๋ค.
2. Option/Maybe (Null/Undefined ๊ฐ ์ฒ๋ฆฌ)
Option/Maybe ํ์ ์ ๊ฐ์ด ์กด์ฌํ ์๋ ์๊ณ ์กด์ฌํ์ง ์์ ์๋ ์๋ ์ํฉ์ ๋ํ๋ด๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ด๋ null ๊ฒ์ฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ๋ ์์ ํ๊ณ ๋ช ์์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก null ๋๋ undefined ๊ฐ์ ์ฒ๋ฆฌํ๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ (๊ฐ๋จํ Option ๊ตฌํ ์ฌ์ฉ):
class Option {
constructor(value) {
this.value = value;
}
static Some(value) {
return new Option(value);
}
static None() {
return new Option(null);
}
map(fn) {
if (this.value === null || this.value === undefined) {
return Option.None();
} else {
return Option.Some(fn(this.value));
}
}
getOrElse(defaultValue) {
return this.value === null || this.value === undefined ? defaultValue : this.value;
}
}
const maybeName = Option.Some("Alice");
const uppercaseName = maybeName.map(name => name.toUpperCase()); // Option.Some("ALICE")
const noName = Option.None();
const uppercaseNoName = noName.map(name => name ? name.toUpperCase() : null); // Option.None()
์ฌ๊ธฐ์ Option ํ์
์ ๊ฐ์ ์ ์ฌ์ ๋ถ์ฌ๋ฅผ ์บก์ํํฉ๋๋ค. map ํจ์๋ ๊ฐ์ด ์กด์ฌํ ๊ฒฝ์ฐ์๋ง ๋ณํ(name => name.toUpperCase())์ ์ ์ฉํ๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด Option.None()์ ๋ฐํํ์ฌ ๋ถ์ฌ ์ํ๋ฅผ ์ ํํฉ๋๋ค.
3. ํธ๋ฆฌ ๊ตฌ์กฐ
ํํฐ๋ ํธ๋ฆฌ์ ๊ฐ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ์๋ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. map ์ฐ์ฐ์ ํธ๋ฆฌ์ ๊ฐ ๋
ธ๋์ ํจ์๋ฅผ ์ ์ฉํฉ๋๋ค.
์์ (๊ฐ๋ ์ ):
tree.map(node => processNode(node));
๊ตฌ์ฒด์ ์ธ ๊ตฌํ์ ํธ๋ฆฌ ๊ตฌ์กฐ์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ์ง๋ง, ํต์ฌ ์์ด๋์ด๋ ๋์ผํฉ๋๋ค: ๊ตฌ์กฐ ์์ฒด๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ๊ตฌ์กฐ ๋ด์ ๊ฐ ๊ฐ์ ํจ์๋ฅผ ์ ์ฉํ๋ ๊ฒ์ ๋๋ค.
ํํฐ ๋ฒ์น
์ ์ ํ ํํฐ๊ฐ ๋๊ธฐ ์ํด์๋ ๋ ๊ฐ์ง ๋ฒ์น์ ์ค์ํด์ผ ํฉ๋๋ค:
- ํญ๋ฑ ๋ฒ์น(Identity Law):
map(x => x, functor) === functor(ํญ๋ฑ ํจ์๋ก ๋งคํํ๋ฉด ์๋์ ํํฐ๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค). - ๊ฒฐํฉ ๋ฒ์น(Composition Law):
map(f, map(g, functor)) === map(x => f(g(x)), functor)(ํจ์๋ค์ ํฉ์ฑํ์ฌ ๋งคํํ๋ ๊ฒ์, ๋ ํจ์์ ํฉ์ฑ์ธ ๋จ์ผ ํจ์๋ก ๋งคํํ๋ ๊ฒ๊ณผ ๋์ผํด์ผ ํฉ๋๋ค).
์ด ๋ฒ์น๋ค์ map ์ฐ์ฐ์ด ์์ธก ๊ฐ๋ฅํ๊ณ ์ผ๊ด๋๊ฒ ๋์ํ๋๋ก ๋ณด์ฅํ์ฌ ํํฐ๋ฅผ ์ ๋ขฐํ ์ ์๋ ์ถ์ํ๋ก ๋ง๋ค์ด ์ค๋๋ค.
๋ชจ๋๋: ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ ์ฐ์ฐ ์์ํ
๋ชจ๋๋๋ ํํฐ๋ณด๋ค ๋ ๊ฐ๋ ฅํ ์ถ์ํ์ ๋๋ค. ๋ชจ๋๋๋ ์ปจํ ์คํธ ๋ด์์ ๊ฐ์ ์์ฑํ๋ ์ฐ์ฐ๋ค์ ์์๋๋ก ์ฐ๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ฉฐ, ์ปจํ ์คํธ๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์ปจํ ์คํธ์ ์๋ก๋ null ๊ฐ ์ฒ๋ฆฌ, ๋น๋๊ธฐ ์ฐ์ฐ, ์ํ ๊ด๋ฆฌ ๋ฑ์ด ์์ต๋๋ค.
๋ชจ๋๋๊ฐ ํด๊ฒฐํ๋ ๋ฌธ์
Option/Maybe ํ์
์ ๋ค์ ์๊ฐํด ๋ด
์๋ค. ์ ์ฌ์ ์ผ๋ก None์ ๋ฐํํ ์ ์๋ ์ฌ๋ฌ ์ฐ์ฐ์ด ์๋ ๊ฒฝ์ฐ, Option<Option<String>>๊ณผ ๊ฐ์ด ์ค์ฒฉ๋ Option ํ์
์ด ๋ ์ ์์ต๋๋ค. ์ด๋ ๋ด๋ถ ๊ฐ์ผ๋ก ์์
ํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ญ๋๋ค. ๋ชจ๋๋๋ ์ด๋ฌํ ์ค์ฒฉ๋ ๊ตฌ์กฐ๋ฅผ "ํํํ(flatten)"ํ๊ณ ์ฐ์ฐ์ ๊น๋ํ๊ณ ๊ฐ๊ฒฐํ ๋ฐฉ์์ผ๋ก ์ฐ๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
๋ชจ๋๋ ์ ์ํ๊ธฐ
๋ชจ๋๋๋ ๋ ๊ฐ์ง ํต์ฌ ์ฐ์ฐ์ ๊ตฌํํ๋ ํ์
M์
๋๋ค:
- Return (๋๋ Unit): ๊ฐ์ ๋ฐ์ ๋ชจ๋๋์ ์ปจํ ์คํธ๋ก ๊ฐ์ธ๋ ํจ์์ ๋๋ค. ์ผ๋ฐ ๊ฐ์ ๋ชจ๋๋ ์ธ๊ณ๋ก ๋์ด์ฌ๋ฆฝ๋๋ค.
- Bind (๋๋ FlatMap): ๋ชจ๋๋์ ๋ชจ๋๋๋ฅผ ๋ฐํํ๋ ํจ์๋ฅผ ๋ฐ์, ๋ชจ๋๋ ๋ด๋ถ์ ๊ฐ์ ํจ์๋ฅผ ์ ์ฉํ๊ณ ์๋ก์ด ๋ชจ๋๋๋ฅผ ๋ฐํํ๋ ํจ์์ ๋๋ค. ์ด๊ฒ์ด ๋ชจ๋๋ ์ปจํ ์คํธ ๋ด์์ ์ฐ์ฐ์ ์์ํํ๋ ํต์ฌ์ ๋๋ค.
์๊ทธ๋์ฒ๋ ์ผ๋ฐ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
return :: a -> M a
bind :: (a -> M b) -> M a -> M b (์ข
์ข
flatMap ๋๋ >>=์ผ๋ก ํ๊ธฐ๋จ)
๋ชจ๋๋์ ์์
1. Option/Maybe (๋ค์ ํ๋ฒ!)
Option/Maybe ํ์
์ ํํฐ์ผ ๋ฟ๋ง ์๋๋ผ ๋ชจ๋๋์ด๊ธฐ๋ ํฉ๋๋ค. ์ด์ ์ ์๋ฐ์คํฌ๋ฆฝํธ Option ๊ตฌํ์ flatMap ๋ฉ์๋๋ฅผ ์ถ๊ฐํด ๋ณด๊ฒ ์ต๋๋ค:
class Option {
constructor(value) {
this.value = value;
}
static Some(value) {
return new Option(value);
}
static None() {
return new Option(null);
}
map(fn) {
if (this.value === null || this.value === undefined) {
return Option.None();
} else {
return Option.Some(fn(this.value));
}
}
flatMap(fn) {
if (this.value === null || this.value === undefined) {
return Option.None();
} else {
return fn(this.value);
}
}
getOrElse(defaultValue) {
return this.value === null || this.value === undefined ? defaultValue : this.value;
}
}
const getName = () => Option.Some("Bob");
const getAge = (name) => name === "Bob" ? Option.Some(30) : Option.None();
const age = getName().flatMap(getAge).getOrElse("Unknown"); // Option.Some(30) -> 30
const getNameFail = () => Option.None();
const ageFail = getNameFail().flatMap(getAge).getOrElse("Unknown"); // Option.None() -> Unknown
flatMap ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์ค์ฒฉ๋ Option ํ์
์ผ๋ก ๋๋์ง ์๊ณ Option ๊ฐ์ ๋ฐํํ๋ ์ฐ์ฐ๋ค์ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค. ๋ง์ฝ ์ด๋ค ์ฐ์ฐ์ด๋ผ๋ None์ ๋ฐํํ๋ฉด, ์ ์ฒด ์ฒด์ธ์ด ๋จ๋ฝ(short-circuits)๋์ด ๊ฒฐ๊ณผ์ ์ผ๋ก None์ด ๋ฉ๋๋ค.
2. Promise (๋น๋๊ธฐ ์ฐ์ฐ)
Promise๋ ๋น๋๊ธฐ ์ฐ์ฐ์ ์ํ ๋ชจ๋๋์
๋๋ค. return ์ฐ์ฐ์ ๋จ์ํ ํด๊ฒฐ๋(resolved) Promise๋ฅผ ์์ฑํ๋ ๊ฒ์ด๊ณ , bind ์ฐ์ฐ์ ๋น๋๊ธฐ ์ฐ์ฐ๋ค์ ํจ๊ป ์ฐ๊ฒฐํ๋ then ๋ฉ์๋์
๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ์์ :
const fetchUserData = (userId) => {
return fetch(`https://api.example.com/users/${userId}`)
.then(response => response.json());
};
const fetchUserPosts = (user) => {
return fetch(`https://api.example.com/posts?userId=${user.id}`)
.then(response => response.json());
};
const processData = (posts) => {
// ์ผ๋ถ ์ฒ๋ฆฌ ๋ก์ง
return posts.length;
};
// .then()์ผ๋ก ์ฒด์ด๋ (๋ชจ๋๋ bind)
fetchUserData(123)
.then(user => fetchUserPosts(user))
.then(posts => processData(posts))
.then(result => console.log("Result:", result))
.catch(error => console.error("Error:", error));
์ด ์์ ์์ ๊ฐ .then() ํธ์ถ์ bind ์ฐ์ฐ์ ๋ํ๋
๋๋ค. ์ด๊ฒ์ ๋น๋๊ธฐ ์ฐ์ฐ๋ค์ ํจ๊ป ์ฐ๊ฒฐํ์ฌ ๋น๋๊ธฐ ์ปจํ
์คํธ๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ๋ง์ฝ ์ด๋ค ์ฐ์ฐ์ด ์คํจํ๋ฉด(์ค๋ฅ๋ฅผ ๋ฐ์์ํค๋ฉด), .catch() ๋ธ๋ก์ด ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ์ฌ ํ๋ก๊ทธ๋จ์ด ์ค๋จ๋๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
3. ์ํ ๋ชจ๋๋ (์ํ ๊ด๋ฆฌ)
์ํ ๋ชจ๋๋(State Monad)๋ฅผ ์ฌ์ฉํ๋ฉด ์ผ๋ จ์ ์ฐ์ฐ ๋ด์์ ์ํ๋ฅผ ์๋ฌต์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์ต๋๋ค. ์ํ๋ฅผ ์ธ์๋ก ๋ช ์์ ์ผ๋ก ์ ๋ฌํ์ง ์๊ณ ์ฌ๋ฌ ํจ์ ํธ์ถ์ ๊ฑธ์ณ ์ํ๋ฅผ ์ ์งํด์ผ ํ๋ ์ํฉ์์ ํนํ ์ ์ฉํฉ๋๋ค.
๊ฐ๋ ์ ์์ (๊ตฌํ์ ๋งค์ฐ ๋ค์ํ ์ ์์):
// ๋จ์ํ๋ ๊ฐ๋
์ ์์
const stateMonad = {
state: { count: 0 },
get: () => stateMonad.state.count,
put: (newCount) => {stateMonad.state.count = newCount;},
bind: (fn) => fn(stateMonad.state)
};
const increment = () => {
return stateMonad.bind(state => {
stateMonad.put(state.count + 1);
return stateMonad.state; // ๋๋ 'stateMonad' ์ปจํ
์คํธ ๋ด์์ ๋ค๋ฅธ ๊ฐ ๋ฐํ
});
};
increment();
increment();
console.log(stateMonad.get()); // Output: 2
์ด๊ฒ์ ๋จ์ํ๋ ์์ ์ด์ง๋ง ๊ธฐ๋ณธ์ ์ธ ์์ด๋์ด๋ฅผ ๋ณด์ฌ์ค๋๋ค. ์ํ ๋ชจ๋๋๋ ์ํ๋ฅผ ์บก์ํํ๊ณ , bind ์ฐ์ฐ์ ํตํด ์ํ๋ฅผ ์๋ฌต์ ์ผ๋ก ์์ ํ๋ ์ฐ์ฐ๋ค์ ์์๋๋ก ์คํํ ์ ์์ต๋๋ค.
๋ชจ๋๋ ๋ฒ์น
์ ์ ํ ๋ชจ๋๋๊ฐ ๋๊ธฐ ์ํด์๋ ์ธ ๊ฐ์ง ๋ฒ์น์ ์ค์ํด์ผ ํฉ๋๋ค:
- ์ข์ธก ํญ๋ฑ ๋ฒ์น(Left Identity):
bind(f, return(x)) === f(x)(๊ฐ์ ๋ชจ๋๋๋ก ๊ฐ์ผ ๋ค์ ํจ์์ ๋ฐ์ธ๋ฉํ๋ ๊ฒ์ ๊ฐ์ ํจ์์ ์ง์ ์ ์ฉํ๋ ๊ฒ๊ณผ ๊ฐ์์ผ ํฉ๋๋ค). - ์ฐ์ธก ํญ๋ฑ ๋ฒ์น(Right Identity):
bind(return, m) === m(๋ชจ๋๋๋ฅผreturnํจ์์ ๋ฐ์ธ๋ฉํ๋ฉด ์๋์ ๋ชจ๋๋๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค). - ๊ฒฐํฉ ๋ฒ์น(Associativity):
bind(g, bind(f, m)) === bind(x => bind(g, f(x)), m)(๋ชจ๋๋๋ฅผ ๋ ํจ์์ ์์ฐจ์ ์ผ๋ก ๋ฐ์ธ๋ฉํ๋ ๊ฒ์, ๋ ํจ์์ ํฉ์ฑ์ธ ๋จ์ผ ํจ์์ ๋ฐ์ธ๋ฉํ๋ ๊ฒ๊ณผ ๊ฐ์์ผ ํฉ๋๋ค).
์ด ๋ฒ์น๋ค์ return ๋ฐ bind ์ฐ์ฐ์ด ์์ธก ๊ฐ๋ฅํ๊ณ ์ผ๊ด๋๊ฒ ๋์ํ๋๋ก ๋ณด์ฅํ์ฌ ๋ชจ๋๋๋ฅผ ๊ฐ๋ ฅํ๊ณ ์ ๋ขฐํ ์ ์๋ ์ถ์ํ๋ก ๋ง๋ค์ด ์ค๋๋ค.
ํํฐ vs. ๋ชจ๋๋: ์ฃผ์ ์ฐจ์ด์
๋ชจ๋๋๋ ํํฐ์ด์ง๋ง(๋ชจ๋๋๋ ๋งคํ์ด ๊ฐ๋ฅํด์ผ ํจ), ์ฃผ์ ์ฐจ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ํํฐ๋ ์ปจํ ์คํธ *๋ด๋ถ*์ ๊ฐ์ ํจ์๋ฅผ ์ ์ฉํ๋ ๊ฒ๋ง ํ์ฉํฉ๋๋ค. ๋์ผํ ์ปจํ ์คํธ ๋ด์์ ๊ฐ์ ์์ฑํ๋ ์ฐ์ฐ๋ค์ ์์๋๋ก ์ฐ๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ง ์์ต๋๋ค.
- ๋ชจ๋๋๋ ์ปจํ ์คํธ ๋ด์์ ๊ฐ์ ์์ฑํ๋ ์ฐ์ฐ๋ค์ ์์๋๋ก ์ฐ๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ฉฐ, ์ปจํ ์คํธ๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ฐ์ฐ๋ค์ ํจ๊ป ์ฐ๊ฒฐํ๊ณ ๋ณต์กํ ๋ก์ง์ ๋ ์ฐ์ํ๊ณ ์กฐํฉ ๊ฐ๋ฅํ ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
- ๋ชจ๋๋๋ ์ปจํ
์คํธ ๋ด์์ ์ฐ์ฐ์ ์์ํํ๋ ๋ฐ ํ์์ ์ธ
flatMap(๋๋bind) ์ฐ์ฐ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ํํฐ๋map์ฐ์ฐ๋ง ๊ฐ์ง๊ณ ์์ต๋๋ค.
๋ณธ์ง์ ์ผ๋ก, ํํฐ๋ ๋ณํํ ์ ์๋ ์ปจํ ์ด๋์ธ ๋ฐ๋ฉด, ๋ชจ๋๋๋ ํ๋ก๊ทธ๋๋ฐ ๊ฐ๋ฅํ ์ธ๋ฏธ์ฝ๋ก ๊ณผ ๊ฐ์ต๋๋ค. ์ฆ, ๊ณ์ฐ์ด ์ด๋ป๊ฒ ์์ํ๋๋์ง๋ฅผ ์ ์ํฉ๋๋ค.
ํํฐ์ ๋ชจ๋๋ ์ฌ์ฉ์ ์ด์
- ์ฝ๋ ๊ฐ๋ ์ฑ ํฅ์: ํํฐ์ ๋ชจ๋๋๋ ๋ ์ ์ธ์ ์ธ ํ๋ก๊ทธ๋๋ฐ ์คํ์ผ์ ์ด์งํ์ฌ ์ฝ๋๋ฅผ ๋ ์ฝ๊ฒ ์ดํดํ๊ณ ์ถ๋ก ํ ์ ์๊ฒ ๋ง๋ญ๋๋ค.
- ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ ์ฆ๊ฐ: ํํฐ์ ๋ชจ๋๋๋ ๋ค์ํ ๋ฐ์ดํฐ ๊ตฌ์กฐ ๋ฐ ์ฐ์ฐ๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์๋ ์ถ์ ๋ฐ์ดํฐ ํ์ ์ผ๋ก, ์ฝ๋ ์ฌ์ฌ์ฉ์ ์ด์งํฉ๋๋ค.
- ํ ์คํธ ์ฉ์ด์ฑ ํฅ์: ํํฐ์ ๋ชจ๋๋์ ์ฌ์ฉ์ ํฌํจํ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์์น์ ์ฝ๋๋ฅผ ๋ ์ฝ๊ฒ ํ ์คํธํ ์ ์๊ฒ ๋ง๋ญ๋๋ค. ์์ ํจ์๋ ์์ธก ๊ฐ๋ฅํ ์ถ๋ ฅ์ ๊ฐ์ง๋ฉฐ ๋ถ์ ํจ๊ณผ๊ฐ ์ต์ํ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
- ๋์์ฑ ๋จ์ํ: ๋ถ๋ณ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ์์ ํจ์๋ ๊ณต์ ๊ฐ๋ณ ์ํ์ ๋ํด ๊ฑฑ์ ํ ํ์๊ฐ ์์ผ๋ฏ๋ก ๋์์ฑ ์ฝ๋๋ฅผ ๋ ์ฝ๊ฒ ์ถ๋ก ํ ์ ์๊ฒ ๋ง๋ญ๋๋ค.
- ๋ ๋์ ์ค๋ฅ ์ฒ๋ฆฌ: Option/Maybe์ ๊ฐ์ ํ์ ์ null ๋๋ undefined ๊ฐ์ ์ฒ๋ฆฌํ๋ ๋ ์์ ํ๊ณ ๋ช ์์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ฌ ๋ฐํ์ ์ค๋ฅ์ ์ํ์ ์ค์ ๋๋ค.
์ค์ ์ฌ์ฉ ์ฌ๋ก
ํํฐ์ ๋ชจ๋๋๋ ๋ค์ํ ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ๋ฌ ๋๋ฉ์ธ์ ๊ฑธ์ณ ์ฌ์ฉ๋ฉ๋๋ค:
- ์น ๊ฐ๋ฐ: ๋น๋๊ธฐ ์ฐ์ฐ์ ์ํ Promise, ์ ํ์ ํผ ํ๋ ์ฒ๋ฆฌ๋ฅผ ์ํ Option/Maybe, ๊ทธ๋ฆฌ๊ณ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ข ์ข ๋ชจ๋๋ ๊ฐ๋ ์ ํ์ฉํฉ๋๋ค.
- ๋ฐ์ดํฐ ์ฒ๋ฆฌ: ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์์น์ ํฌ๊ฒ ์์กดํ๋ ์ํ์น ์คํํฌ(Apache Spark)์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋๊ท๋ชจ ๋ฐ์ดํฐ์ ์ ๋ณํ์ ์ ์ฉํฉ๋๋ค.
- ๊ฒ์ ๊ฐ๋ฐ: ํจ์ํ ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ(FRP) ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฒ์ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ณ ๋น๋๊ธฐ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
- ๊ธ์ต ๋ชจ๋ธ๋ง: ์์ธก ๊ฐ๋ฅํ๊ณ ํ ์คํธ ๊ฐ๋ฅํ ์ฝ๋๋ก ๋ณต์กํ ๊ธ์ต ๋ชจ๋ธ์ ๊ตฌ์ถํฉ๋๋ค.
- ์ธ๊ณต ์ง๋ฅ: ๋ถ๋ณ์ฑ๊ณผ ์์ ํจ์์ ์ค์ ์ ๋๊ณ ๋จธ์ ๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํํฉ๋๋ค.
ํ์ต ์๋ฃ
ํํฐ์ ๋ชจ๋๋์ ๋ํ ์ดํด๋ฅผ ๋๊ธฐ ์ํ ๋ช ๊ฐ์ง ์๋ฃ์ ๋๋ค:
- ์์ : "Functional Programming in Scala" (Paul Chiusano, Rรบnar Bjarnason), "Haskell Programming from First Principles" (Chris Allen, Julie Moronuki), "Professor Frisby's Mostly Adequate Guide to Functional Programming" (Brian Lonsdorf)
- ์จ๋ผ์ธ ๊ฐ์ข: Coursera, Udemy, edX์์ ๋ค์ํ ์ธ์ด๋ก ๋ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ๊ฐ์ข๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ๋ฌธ์: ํ์ค์ผ์ ํํฐ ๋ฐ ๋ชจ๋๋ ๋ฌธ์, ์ค์นผ๋ผ์ Future ๋ฐ Option ๋ฌธ์, Ramda ๋ฐ Folktale๊ณผ ๊ฐ์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ.
- ์ปค๋ฎค๋ํฐ: Stack Overflow, Reddit ๋ฐ ๊ธฐํ ์จ๋ผ์ธ ํฌ๋ผ์ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ปค๋ฎค๋ํฐ์ ์ฐธ์ฌํ์ฌ ์ง๋ฌธํ๊ณ ์๋ จ๋ ๊ฐ๋ฐ์๋ก๋ถํฐ ๋ฐฐ์ฐ์ธ์.
๊ฒฐ๋ก
ํํฐ์ ๋ชจ๋๋๋ ์ฝ๋์ ํ์ง, ์ ์ง๋ณด์์ฑ, ํ ์คํธ ์ฉ์ด์ฑ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์๋ ๊ฐ๋ ฅํ ์ถ์ํ์ ๋๋ค. ์ฒ์์๋ ๋ณต์กํด ๋ณด์ผ ์ ์์ง๋ง, ๊ธฐ๋ณธ ์์น์ ์ดํดํ๊ณ ์ค์ ์์ ๋ฅผ ํ์ํ๋ฉด ๊ทธ ์ ์ฌ๋ ฅ์ ๋ฐํํ ์ ์์ต๋๋ค. ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์์น์ ๋ฐ์๋ค์ด๋ฉด, ๋ณต์กํ ์ํํธ์จ์ด ๊ฐ๋ฐ ๊ณผ์ ๋ฅผ ๋ ์ฐ์ํ๊ณ ํจ๊ณผ์ ์ธ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ ์ ์๋ ๋ฅ๋ ฅ์ ๊ฐ์ถ๊ฒ ๋ ๊ฒ์ ๋๋ค. ์ฐ์ต๊ณผ ์คํ์ ์ง์คํ๋ ๊ฒ์ ์์ง ๋ง์ธ์. ํํฐ์ ๋ชจ๋๋๋ฅผ ๋ ๋ง์ด ์ฌ์ฉํ ์๋ก ๋ ์ง๊ด์ ์ผ๋ก ๋ค๊ฐ์ฌ ๊ฒ์ ๋๋ค.