functional composition - Lee-hyuna/33-js-concepts-kr GitHub Wiki

ํ•จ์ˆ˜์˜ ํ•ฉ์„ฑ - compose() ์™€ pipe()

์›๋ฌธ: Functional Composition: compose() and pipe()

ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์ด๋‹ค.

ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๊ธฐ๋ณธ ์•„์ด๋””์–ด๋Š” ํ•จ์ˆ˜๋“ค์„ ์—ฎ๋Š” ๊ฒƒ์ด๋‹ค. ํ•œ ๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์€ ํ•จ์ˆ˜๋“ค์„ ์กฐ๋ฆฝํ•˜์—ฌ ํ•˜์—ฌ ๋ณต์žกํ•œ ๊ธฐ๋Šฅ ์„ ์ƒ์„ฑํ•œ๋‹ค.

์ด๊ฒƒ์ด ๋ฐ”๋กœ **ํ•จ์ˆ˜์˜ ํ•ฉ์„ฑ(function composition)**์ด๋‹ค. ์ด๊ฒƒ์€ ํ•œ ํ•จ์ˆ˜์˜ ์ถœ๋ ฅ์„ ๋‹ค๋ฅธ ํ•จ์ˆ˜์˜ ์ž…๋ ฅ ์œผ๋กœ ์ „๋‹ฌํ•จ์œผ๋กœ์จ ๋‹ฌ์„ฑ๋œ๋‹ค.

ํ•ฉ์„ฑ์˜ ๊ธฐ์ดˆ

์•„๋ž˜์˜ ์ˆ˜ํ•™ ํ•จ์ˆ˜๋ฅผ ์‚ดํŽด๋ณด์ž.

f(x) = x + 2

g(x) = 4x

์œ„์˜ ํ•จ์ˆ˜๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ํ•ฉ์„ฑํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

f(g(x)) = 4x + 2
// ๋˜๋Š”
g(f(x)) = 4x + 8

๋งจ ์ฒ˜์Œ ์ˆ˜ํ•™ ํ•จ์ˆ˜๋ฅผ ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค,

const addTwo = x => x + 2;

const multiplyByFour = x => 4 * x;

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ฉ์„ฑํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

const composed1 = X => addTwo( multiplyByFour(X) );
// ๋˜๋Š”
const composed2 = X => multiplyByFour( addTwo(X) );

๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

/resource/yongkwan/33/01.gif

๋ฌธ์ œ

๋ฌธ์ œ๋Š” ์ด์™€ ๊ฐ™์ด ํ•จ์ˆ˜๋ฅผ ํ•ฉ์„ฑํ•˜๋Š” ๊ฒƒ์€ ์ ํ•ฉ ํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋งŽ์€ ํ•จ์ˆ˜๋“ค์ด ์กด์žฌํ•œ๋‹ค๋ฉด, ๊ทธ ํ•จ์ˆ˜๋“ค์˜ ํ•ฉ์„ฑ์€ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ณด์ผ ๊ฒƒ์ด๋‹ค.

func1(func2(func3(func4(func5(func6(func7(x)))))))

์ฝ๊ธฐ ์ฐธ ์–ด๋ ค์šด ์ฝ”๋“œ๋‹ค.

์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ• ๊นŒ? ๋‹ต์€ compose()์™€ pipe()์ด๋‹ค.

compose()

compose()๋Š” **์ธ์ž๋ฅผ ํ•จ์ˆ˜๋กœ ๋ฐ›๋Š”๋ฐ **, ๋ฐ์ดํ„ฐ ํ”Œ๋กœ์šฐ๋Š” ์˜ค๋ฅธ์ชฝ์—์„œ ์™ผ์ชฝ์œผ๋กœ์ด์–ด์ง€๋ฉฐ ์ธ์ž๋“ค์„ ๊ฒฐํ•ฉํ•œ๋‹ค. ๊ทธ ๋‹ค์Œ ๊ฒฐํ•ฉ ๋œ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

/resource/yongkwan/33/02.png

๊ตฌํ˜„์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

const compose = (...fns) => {
	 return x => {
		return fns.reduceRight((y, f) => f(y), x)
	 }
 }

์‚ฌ์šฉ ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

const addTwo = x => x + 2;
const multiplyByFour = x => 4 * x;
const composeFunc = compose(multiplyByFour, addTwo)
const result = composeFunc(3)

์™ผ์ชฝ <-- ์˜ค๋ฅธ์ชฝ์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ํ๋ฅด๊ณ  ์žˆ์Œ์„ ์•Œ์ˆ˜ ์žˆ๋‹ค.

20 <-- multiplyByFour(5) <-- 5 <-- addTwo(3) <-- 3

์ด์ „์— ํ•จ์ˆ˜์˜ ํ•ฉ์„ฑ๋ณด๋‹ค ํ›จ์”ฌ ๋‚ซ๋‹ค. ๐Ÿ˜Š

pipe()

pipe()๋Š” compose()์™€ ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค. ์œ ์ผํ•œ ์ฐจ์ด๊ฐ€ ํ•˜๋‚˜ ์žˆ๋Š”๋ฐ, pipe()๋Š” ๋ฐ์ดํ„ฐ ์ด๋™์ด ์™ผ์ชฝ --> ์˜ค๋ฅธ์ชฝ์œผ๋กœ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์ด๋‹ค.:

/resource/yongkwan/33/03.png

๊ตฌํ˜„์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ์œ ์ผํ•œ ์ฐจ์ด์ ์€ Array.prototype.reduceRight๋Œ€์‹  Array.prototype.reduce์ด ์‚ฌ์šฉ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

const pipe = (...fns) => {
	 return x => {
		return fns.reduce((y, f) => f(y), x)
	 }
 }

์‚ฌ์šฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ์œ ์ผํ•œ ์ฐจ์ด์ ์€ addTwo ์™€ multiplyByFour ๊ฐ€ ์„œ๋กœ ๋ฐ”๋€ ์œ„์น˜๋‹ค. ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ ์ด๋Š” pipe()์—์„œ ์™ผ์ชฝ --> ์˜ค๋ฅธ์ชฝ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ด๋™ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

const addTwo = x => x + 2;
const multiplyByFour = x => 4 * x;
const pipeFunc = pipe(addTwo, multiplyByFour)
const result = pipeFunc(3)

์™ผ์ชฝ --> ์˜ค๋ฅธ์ชฝ ๋ฐ์ดํ„ฐ ํ๋ฆ„์ด ๋” ์ž์—ฐ ์Šค๋Ÿฝ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ์ธ์ ์œผ๋กœ compose()๋ณด๋‹ค pipe()๋ฅผ ์„ ํ˜ธํ•œ๋‹ค .

์˜ค๋ฅธ์ชฝ์—์„œ ์™ผ์ชฝ์œผ๋กœ ์“ฐ๋Š” ์–ธ์–ด ์ด์šฉ์ž, ์ˆ˜ํ•™์ž๋Š” compose()๋ฅผ ์„ ํ˜ธํ•  ๊ฒƒ ๊ฐ™๋‹ค.