diff --git "a/contents/09.\353\251\224\353\252\250\354\235\264\354\240\234\354\235\264\354\205\230/1.memoize\355\225\250\354\210\230.md" "b/contents/09.\353\251\224\353\252\250\354\235\264\354\240\234\354\235\264\354\205\230/1.memoize\355\225\250\354\210\230.md"
new file mode 100644
index 0000000..bc8e249
--- /dev/null
+++ "b/contents/09.\353\251\224\353\252\250\354\235\264\354\240\234\354\235\264\354\205\230/1.memoize\355\225\250\354\210\230.md"
@@ -0,0 +1,373 @@
+#### [back](../../README.md) | write by [sangcho][sangcho]
+
+# 1. memoize 함수
+
+> 이 글은 함수형 자바스크립트 프로그래밍을 참고하여 기록하였습니다.
+
+
+
+메모이제이션은 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여, 프로그램 실행 속도를 빠르게 하는 기술.
+
+## 1. 메모이제이션 코드로 이해하기
+
+#### 1.1 memoize
+
+```typescript
+function memoize(func) { // memoize는 함수를 받는 함수다.
+ var cache = {}; // 이 객체에 결과를 남겨둘 것이다.
+ return function(arg) {
+ if (cache[arg]) { // 이미 동일 인자에 대한 결과가 있으면 리턴
+ console.log('캐시로 결과 바로 리턴', arg);
+ return cache[arg];
+ }
+ console.log('본체 실행', arg);
+ return cache[arg] = func.apply(this, arguments); // 받아둔 함수를 실행하면서 결과를 cache에 남겨둠
+ }
+}
+
+------------------------------------------------------------
+// 실행
+var mult5 = memoize(function(a) {
+ return a * 5;
+});
+
+console.log( mult5(1) );
+// 본체 실행 1
+// 5
+
+console.log( mult5(2) );
+// 본체 실행 2
+// 10
+
+console.log( mult5(1) );
+// 캐시로 결과 바로 리턴 1
+// 5
+
+console.log( mult5(1) );
+// 캐시로 결과 바로 리턴 1
+// 5
+```
+[실행코드](https://codesandbox.io/s/hamsuhyeongpeurogeuraeming-9jang-lzh8jz?file=/src/9.1.js)
+
+
+
+#### 1.2 memoize의 한계
+
+```typescript
+var add = memoize(function (a, b) {
+ return a + b;
+});
+
+console.log(add(3, 5));
+// 본체 실행 3
+// 8
+
+console.log(add(3, 10));
+// 캐시로 결과 바로 리턴 3
+// 8
+// 캐시가 동작했지만 3에만 의존하기 때문에 오류
+
+var keys = memoize(function (obj) {
+ return _.keys(obj);
+});
+
+console.log(keys({ a: 1, b: 2 }));
+// 본체 실행 Object {a: 1, b: 2}
+// ["a", "b"]
+
+console.log(keys({ a: 1, b: 2 }));
+// 캐시로 결과 바로 리턴 Object {a: 1, b: 2}
+// ["a", "b"]
+
+console.log(keys({ a: 10, b: 20 }));
+// 캐시로 결과 바로 리턴 Object {a: 1, b: 2}
+// ["a", "b"]
+// 잘 동작하는 듯 했지만 cache가 { [object Object]: ... } 이런식으로 되기 때문에 오류
+```
+[실행코드](https://codesandbox.io/s/hamsuhyeongpeurogeuraeming-9jang-lzh8jz?file=/src/9.1.js)
+
+
+
+## 2. Underscore.js의 _.memoize
+
+#### 2.1 _.memoize
+
+```typescript
+_.memoize = function (func, hasher) {
+ // 본체 함수와 hasher 함수를 받음
+ var memoize = function (key) {
+ var cache = memoize.cache;
+ var address = "" + (hasher ? hasher.apply(this, arguments) : key);
+ // hasher가 있으면 hasher에게도 인자들을 넘겨 cache의 key로 사용할 address를 생성
+ // 없으면 첫 번째 인자를 그대로 사용
+ if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
+ // (1) 결과가 없을 때만 함수를 실행하여 cache에 담음
+ return cache[address]; // 결과 리턴
+ };
+ memoize.cache = {}; // (2) 클로저를 사용하지 않고 리턴할 함수 자체에 cache를 달아둠
+ return memoize;
+};
+```
+
+- Underscore.js의 memoize는 cache의 key를 함수를 통해 만드는 것이 가능
+- (1)에서 _.has를 사용한 이유는 캐시한 결과 값이 null, 0, undefined일 수 있기 때문.
+- (2)에서 함수에 .cache를 쓴 이유는 개발자가 메모리 관리를 할 수 있도록 하기 위함 -> 클로저를 사용할 경우 cache에 담긴 실행 결과들이 메모리에 상주하고 있어야 하기 때문.
+
+## 3. Partial.js의 _.memoize2
+
+#### 3.1 _.memoize2
+
+```typescript
+var f1 = _.memoize2(function(obj) {
+ console.log('함수 본체에 들어옴');
+ return obj.a + 10;
+});
+
+var obj1 = { a: 1 };
+var obj2 = { a: 2 };
+
+console.log( f1(obj1) );
+// 함수 본체에 들어옴
+// {a:11}
+console.log( f1(obj1) );
+// {a:11} (캐시 사용)
+console.log( f1(obj1) );
+// {a:11} (캐시 사용)
+
+console.log( f1(obj2) );
+// 함수 본체에 들어옴
+// {a:12}
+console.log( f1(obj2) );
+// {a:12} (캐시 사용)
+```
+
+- _.memoize가 캐시를 함수에 기록, _.memoize2는 캐시를 인자에 기록
+- _.memoize2는 불변 객체 컨셉과 함께 사용하기 위해 만든 함수
+- 각 함수들에 대한 결과값을 인자로 사용한 사용된 객체에 담아두므로 한 번 사용하고 버리는 객체 -> 메모리에서 비워짐
+- 사용한 인자에 결과 캐시가 쌓이므로 값의 유무에 따라 자동으로 메모리가 관리
+
+#### 3.2 mutable
+
+```typescript
+var evens = _.memoize2(function(list) {
+ console.log('함수 본체에 들어와서 loop 실행');
+ return _.filter(list, function(num) {
+ return num % 2 == 0;
+ })
+});
+
+var list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+console.log( evens(list) );
+// 함수 본체에 들어와서 loop 실행
+// [2, 4, 6, 8, 10]
+console.log( evens(list) );
+// [2, 4, 6, 8, 10] (캐시를 사용하여 loop를 돌지 않음)
+
+list.push(11); // mutable
+list.push(12); // mutable
+console.log( list );
+// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+
+console.log( evens(list) );
+// [2, 4, 6, 8, 10] (캐시가 사용되어 10이 그대로 남음)
+```
+
+#### 3.3 immutable
+
+```typescript
+var list2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+console.log( evens(list2) );
+// 함수 본체에 들어와서 loop 실행
+// [2, 4, 6, 8, 10]
+console.log( evens(list2) );
+// [2, 4, 6, 8, 10] (캐시를 사용하여 loop를 돌지 않음)
+
+list2 = list2.concat(11, 12); // immutable
+console.log( list2 );
+// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+
+console.log( evens(list2) );
+// 함수 본체에 들어와서 loop 실행
+// [2, 4, 6, 8, 10, 12]
+
+console.log( evens(list2) );
+// [2, 4, 6, 8, 10, 12] (캐시를 사용하여 loop를 돌지 않음)
+```
+
+#### 3.4 _.memoize2 with _.go
+
+```typescript
+var users = [
+ { id: 1, name: "ID", age: 32, count: { review: 3, cart: 5 } },
+ { id: 2, name: "HA", age: 25, count: { review: 8, cart: 4 } },
+ { id: 3, name: "BJ", age: 32, count: { review: 0, cart: 0 } },
+ { id: 4, name: "PJ", age: 28, count: { review: 4, cart: 5 } },
+ { id: 5, name: "JE", age: 27, count: { review: 5, cart: 2 } },
+ { id: 6, name: "JM", age: 32, count: { review: 4, cart: 6 } },
+ { id: 7, name: "JI", age: 31, count: { review: 7, cart: 2 } }
+];
+
+var best_reviewers = _.memoize2(function(list) {
+ console.log('함수 본체에 들어와서 loop 실행');
+ return _.filter(list, function(user) {
+ return user.count.review > 5;
+ })
+});
+
+var cart_is_empty = _.memoize2(function(list) {
+ console.log('함수 본체에 들어와서 loop 실행');
+ return _.filter(list, function(user) {
+ return user.count.cart == 0;
+ })
+});
+
+// _.go: 즉시 실행되는 pipe 라인 함수
+
+_.go(users,
+ best_reviewers,
+ _.pluck('name'),
+ console.log);
+// 함수 본체에 들어와서 loop 실행
+// ["HA", "JI"]
+
+_.go(users,
+ best_reviewers,
+ _.pluck('name'),
+ console.log);
+// ["HA", "JI"] (캐시 사용)
+
+_.go(users,
+ cart_is_empty,
+ _.pluck('name'),
+ console.log);
+// 함수 본체에 들어와서 loop 실행
+// ["BJ"]
+
+_.go(users,
+ cart_is_empty,
+ _.pluck('name'),
+ console.log);
+// ["BJ"] (캐시 사용)
+```
+
+#### 3.5 _.memoize2 with _.im
+
+```typescript
+
+// _.im.set: immutable set 함수
+users = _.im.set(users, '(#3)->count', {
+ review: 10,
+ cart: 1
+});
+// id가 3에 해당하는 객체 갱신
+
+_.go(users,
+ best_reviewers,
+ _.pluck('name'),
+ console.log);
+// 함수 본체에 들어와서 loop 실행
+// ["HA", "BJ", "JI"]
+
+_.go(users,
+ best_reviewers,
+ _.pluck('name'),
+ console.log);
+// ["HA", "BJ", "JI"] (캐시 사용)
+
+_.go(users,
+ cart_is_empty,
+ _.pluck('name'),
+ console.log);
+// 함수 본체에 들어와서 loop 실행
+// []
+
+_.go(users,
+ cart_is_empty,
+ _.pluck('name'),
+ console.log);
+// [] (캐시 사용)
+```
+
+- user는 중첩 구조 데이터 -> 가변으로 값을 변경하면 위 함수들이 캐시에 남은 값을 리턴하는 문제 발생
+- _.im 을 이용하여 값을 변경 -> 캐시도 함께 갱신
+- _.im 을 이용하여 값을 변경 -> 변경이 되지 않은 객체는 살려둠.
+
+#### 3.6 _.memoize2 with _.im + predicate
+
+```typescript
+
+var predicate = _.memoize2(function(user) {
+ console.log('predicate 실행');
+ return user.count.review > 5;
+});
+
+var best_reviewers2 = _.memoize2(function(list) {
+ console.log('함수 본체에 들어와서 loop 실행');
+ return _.filter(list, predicate);
+});
+
+_.go(users,
+ best_reviewers2,
+ _.pluck('name'),
+ console.log);
+// 함수 본체에 들어와서 loop 실행
+// predicate 실행 * 7번 실행
+// ["HA", "BJ", "JI"]
+
+_.go(users,
+ best_reviewers2,
+ _.pluck('name'),
+ console.log);
+// ["HA", "BJ", "JI"] (캐시 사용)
+
+users = _.im.set(users, '(#3)->count->review', 2);
+// BJ의 count.review를 다시 줄임
+
+_.go(users,
+ best_reviewers2,
+ _.pluck('name'),
+ console.log);
+// 함수 본체에 들어와서 loop 실행
+// predicate 실행 * 1번 실행
+// ["HA", "JI"]
+
+```
+
+- users를 새로운 값으로 변경 -> 내부 객체의 BJ만 변경 -> 나머지는 변경하지 않음 -> predicate의 실행 스킵 가능
+- predicate or iteratee 등 반복 실행되는 함수 & 내부가 복잡한 함수에게는 성능적으로 이득
+
+## 3. _.momoize2 내부와 JSON.stringify
+
+```typescript
+
+_.memoize2 = function(mid) {
+ return function(func) {
+ var memoize_id = ++mid;
+ var f = arguments.length == 1 ? func : __.apply(null, arguments);
+ return function(obj) { // 함수로 달아 놓음
+ return _.has(obj._memoize || (obj._memoize = function(){}), memoize_id) ?
+ obj._memoize[memoize_id] : (obj._memoize[memoize_id] = f(obj));
+ }
+ }
+}(0);
+```
+- 필자가 만든 _.memoize2 함수는 인자를 한 개만 받을 수 있음 -> 캐시가 필요한 함수에서 인자가 2개 이상 필요한 경우가 거의 없다고 판단되었기 때문
+- 캐시 객체를 함수로 달아둠 -> 객체에 달린 함수는 JSON.stringify에서 자동으로 지워지기 때문에.....(?)
+
+---
+
+<참고자료>
+
+[책] [#함수형자바스크립트프로그래밍][함수형자바스크립트프로그래밍] - 유인동 지음 -
+
+[사이트]
+
+---
+
+##### 고차함수와 보조함수 end
+
+[함수형자바스크립트프로그래밍]: https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=123715872
+[sangcho]: https://github.com/SangchoKim
+[taeHyen]: https://github.com/rlaxogus0517
+[kangHyen]: https://github.com/bebekh1216
+[sumin]: https://github.com/ttumzzi
diff --git "a/contents/09.\353\251\224\353\252\250\354\235\264\354\240\234\354\235\264\354\205\230/2.\353\266\200\353\266\204\354\240\201\354\232\251.md" "b/contents/09.\353\251\224\353\252\250\354\235\264\354\240\234\354\235\264\354\205\230/2.\353\266\200\353\266\204\354\240\201\354\232\251.md"
new file mode 100644
index 0000000..74d8b32
--- /dev/null
+++ "b/contents/09.\353\251\224\353\252\250\354\235\264\354\240\234\354\235\264\354\205\230/2.\353\266\200\353\266\204\354\240\201\354\232\251.md"
@@ -0,0 +1,297 @@
+#### [back](../../README.md) | write by [sangcho][sangcho]
+
+# 2. 부분 적용
+
+> 이 글은 함수형 자바스크립트 프로그래밍을 참고하여 기록하였습니다.
+
+
+
+## 1. _.partial로 함수 만들기
+
+#### 1.1 _.partial 사용법
+
+```typescript
+var pc = _.partial(console.log, 1);
+pc(2);
+// 결과: 1 2
+// 2 가 오른쪽으로 들어감
+pc(2, 3);
+// 결과: 1 2 3
+// 2, 3이 오른쪽으로 들어감
+
+var pc = _.partial(console.log, _, 2);
+pc(1);
+// 결과: 1 2
+// 1이 왼쪽의 _ 자리에 들어감
+pc(1, 3);
+// 결과: 1 2 3
+// 1이 왼쪽의 _ 자리에 들어가고 3이 오른쪽으로 들어감
+
+var pc = _.partial(console.log, _, _, 3);
+pc(1);
+// 결과: 1 undefined 3
+// 1이 왼쪽의 _ 자리에 들어가고 두 번째 _는 들어오지 않아 undefined가 됨
+pc(1, 2);
+// 결과: 1 2 3
+// 1과 2가 순서대로 _, _를 채움
+pc(1, 2, 4);
+// 결과: 1 2 3 4
+// 1과 2가 순서대로 _, _를 채우고 3의 오른쪽으로 4가 들어감
+
+var pc = _.partial(console.log, _, 2, _, 4);
+pc(1, 3, 5);
+// 결과: 1 2 3 4 5
+// 1을 _ 자리에 채우고 2를 넘겨서 _에 3을 채우고 4의 오른쪽에 5가 들어감
+
+var pc = _.partial(console.log, _, 2, _, _, 5);
+pc(1, 3, 4, 6);
+// 결과: 1 2 3 4 5 6
+// 1을 _ 자리에 채우고 2를 넘겨서 _에 3을 채우고 다음 _에 4를 채우고 5의 오른쪽에 6이 들어감
+```
+[실행코드](https://codesandbox.io/s/hamsuhyeongjabaseukeuribteupeurogeuraeming-th30pc?file=/src/4.2.1.js)
+
+- _.partial 함수를 이용하면 원하는 위치에 인자를 부분적으로 적용할 수 있음.
+
+
+
+#### 1.2 add_all
+
+```typescript
+var add_all = _.partial(_.reduce, _, function(a, b) { return a + b });
+
+add_all([1, 2, 3, 4]);
+// 10
+
+add_all([5, 2]);
+// 7
+```
+[실행코드](https://codesandbox.io/s/hamsuhyeongjabaseukeuribteupeurogeuraeming-th30pc?file=/src/4.2.1.js)
+
+- _.partial을 이용해 _.reduce와 같은 고차 함수에 미리 보조 함수를 적용해 두는 식으로 해당 함수 구현 가능.
+
+
+
+## 2. _.partial과 _.compose로 함수 만들기
+
+```typescript
+_.compose(
+ console.log,
+ function (a) {
+ return a - 2;
+ },
+ function (a) {
+ return a + 5;
+ }
+)(0);
+// console.log <- 5 - 2 <- 0 + 5 <- 0
+// 3
+
+var falsy_values = _.compose(
+ _.partial(_.isEqual, -1), // (1)
+ _.partial(_.findIndex, _, _.identity)
+); // (2)
+
+ console.log( falsy_values([1, true, {}]) );
+// false
+ console.log(falsy_values([0, 1, false]));
+// false
+ console.log(falsy_values([0, "", false]));
+ // true
+
+var some = _.negate(falsy_values); // (3)
+
+ console.log( some([1, true, {}]) );
+ // true
+ console.log( some([0, 1, false]) );
+ // true
+ console.log( some([0, "", false]) );
+ // false
+
+var every = _.compose(
+ _.partial(_.isEqual, -1),
+ _.partial(_.findIndex, _, _.negate(_.identity))
+); // (4)
+
+console.log( every([1, true, {}]) );
+// true
+console.log( every([0, 1, false]) );
+// false
+console.log( every([0, "", false]) );
+// false
+```
+[실행코드](https://codesandbox.io/s/hamsuhyeongjabaseukeuribteupeurogeuraeming-th30pc?file=/src/4.2.2.js)
+
+- _.compose는 오른쪽의 함수를 실행한 결과를 왼쪽의 함수에게 전달하는 것을 반복하는 고차 함수.
+- _.compose는 인자로 함수만 받음.
+
+
+
+## 3. 더 나은 _.partial 함수
+
+#### 3.1 약간은 아쉬운 _.partial 함수
+
+```typescript
+function add(a, b) {
+ return a + b;
+}
+
+function sub(a, b) {
+ return a - b;
+}
+
+function m() {
+ var iter = arguments[arguments.length - 1];
+ arguments.length--;
+ return _.reduce(arguments, iter);
+}
+
+m(100, 50, add);
+// 150
+m(100, 50, 10, add);
+// 160
+m(100, 50, 10, 5, add);
+// 165
+
+m(100, 50, sub);
+// 50
+m(100, 50, 10, sub);
+// 40
+m(100, 50, 10, 5, sub);
+// 35
+
+// 동작가능
+----------------------------------------------------
+// 에러 발생
+
+var f1 = _.partial(m, _, _, _, add);
+// f1은 3개의 인자만 더할 수 있다.
+
+f1(1, 1, 1);
+// 3
+f1(1, 1);
+// NaN
+f1(1, 1, 1, 1);
+// Uncaught TypeError: iteratee is not a function
+// _.reduce에 1이 넘어가면서 에러
+
+```
+[실행코드](https://codesandbox.io/s/hamsuhyeongjabaseukeuribteupeurogeuraeming-th30pc?file=/src/4.2.3.js)
+
+- _.partial 함수는 _로 구분하여 인자가 적용될 위치를 지정해 둘 수 있음 -> 인자 개수가 유동적일 때, 함수의 마지막 인자가 유동적일 때 아쉬운 부분이 존재.
+- f1 함수처럼 맨 왼쪽의 인자나 맨 왼쪽에서 두 번째 인자를 적용해두는 것은 가능
+- 그러나 맨 오른쪽 인자나 맨 오른쪽에서 두 번째에만 인자를 적용하는 경우는 불가능
+
+
+
+#### 3.2 새롭게 보완한 _.partial 함수
+
+```typescript
+var ___ = {};
+_.partial = function(fn) {
+ var args1 = [], args3, len = arguments.length, ___idx = len;
+ for (var i = 1; i < len; i++) {
+ var arg = arguments[i];
+ if (arg == ___ && (___idx = i) && (args3 = [])) continue;
+ if (i < ___idx) args1.push(arg);
+ else args3.push(arg);
+ }
+ return function() { return fn.apply(this, mergeArgs(args1, arguments, args3)); };
+};
+
+function _toUndef(args1, args2, args3) {
+ if (args2) args1 = args1.concat(args2);
+ if (args3) args1 = args1.concat(args3);
+ for (var i = 0, len = args1.length; i < len; i++) if (args1[i] == _) args1[i] = undefined;
+ return args1;
+}
+
+function mergeArgs(args1, args2, args3) {
+ if (!args2.length) return args3 ? _toUndef(args1, args3) : _toUndef(args1.slice());
+
+ var n_args1 = args1.slice(), args2 = _.toArray(args2), i = -1, len = n_args1.length;
+ while (++i < len) if (n_args1[i] == _) n_args1[i] = args2.shift();
+ if (!args3) return _toUndef(n_args1, args2.length ? args2 : undefined);
+
+ var n_arg3 = args3.slice(), i = n_arg3.length;
+ while (i--) if (n_arg3[i] == _) n_arg3[i] = args2.pop();
+ return args2.length ? _toUndef(n_args1, args2, n_arg3) : _toUndef(n_args1, n_arg3);
+}
+```
+- 새로운 구분자 ___가 추가.
+- ___를 기준으로 왼편의 인자들을 왼쪽부터 적용, 오른편의 인자들을 오른쪽부터 적용할 준비를 해 둔 함수를 리턴.
+- 부분 적용된 함수를 실행하면, 그때 받은 인자들로 왼쪽과 오른쪽을 먼저 채운 후, 남은 인자들로 가운데 ___ 자리를 채움.
+
+
+
+#### 3.3 사용법
+
+```typescript
+var pc = _.partial(console.log, ___, 2, 3);
+pc(1);
+// 결과: 1 2 3
+// ___ 자리에 1이 들어가고 2, 3은 맨 오른쪽에 들어감
+pc(1, 4, 5, 6);
+// 결과: 1 4 5 6 2 3
+// ___ 자리에 1, 4, 5, 6이 들어가고 2, 3은 맨 오른쪽에 들어감
+
+var pc = _.partial(console.log, _, 2, ___, 6);
+pc(1, 3, 4, 5);
+// 결과: 1 2 3 4 5 6
+// _에 1이 들어가고 2를 넘어가고 ___ 자리에 3, 4, 5가 채워지고 6이 맨 오른쪽에 들어감
+pc(1, 3, 4, 5, 7, 8, 9);
+// 결과: 1 2 3 4 5 7 8 9 6
+// _에 1이 들어가고 2를 넘어가고 ___ 자리에 3, 4, 5, 7, 8, 9가 채워지고 6이 맨 오른쪽에 들어감
+
+var pc = _.partial(console.log, _, 2, ___, 5, _, 7);
+pc(1);
+// 결과: 1 2 5 undefined 7
+// _ 자리에 1이 들어가고 2와 5사이는 유동적이므로 모이고 5가 들어간 후 _가 undefined로 대체 되고 7이 들어감
+pc(1, 3, 4);
+// 결과: 1 2 3 5 4 7
+// _ 자리에 1이 들어가고 2와 5사이에 3이 들어가고 _ 를 4로 채운 후 7이 들어감
+// 왼쪽의 _ 들이 우선 순위가 제일 높고 ___ 보다 오른쪽의 _ 들이 우선순위가 높음
+pc(1, 3, 4, 6, 8);
+// 결과: 1 2 3 4 6 5 8 7
+// _ 자리에 1이 들어가고 2와 5사이에 3, 4, 6이 들어가고 _ 를 8로 채운 후 7이 들어감
+
+----------------------------------------------------------
+
+// 문제가 있었던 m 함수 다시 적용해보기
+var add_all = _.partial(m, ___, add);
+
+add_all(1, 2, 3, 4);
+// 10
+add_all(1, 2, 3, 4, 5);
+// 15
+
+var sub10 = _.partial(m, ___, 10, sub);
+
+sub10(50);
+// 40
+sub10(50, 20);
+// 20
+sub10(50, 20, 10);
+// 10
+
+```
+- _.partial을 이용하면 인자를 조합하기 위해 함수로 함수를 만드는 경우를 모두 대체 가능.
+- 함수를 조립하고, 함수 합성 패턴(_.chain, _.compose, _.pipeline)등과도 잘 어울림.
+- 함수에 인자를 미리 적용해 두는 기법은 비동기 상황에서도 효율적임.
+
+---
+
+<참고자료>
+
+[책] [#함수형자바스크립트프로그래밍][함수형자바스크립트프로그래밍] - 유인동 지음 -
+
+[사이트]
+
+---
+
+##### 부분 적용 end
+
+[함수형자바스크립트프로그래밍]: https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=123715872
+[sangcho]: https://github.com/SangchoKim
+[taeHyen]: https://github.com/rlaxogus0517
+[kangHyen]: https://github.com/bebekh1216
+[sumin]: https://github.com/ttumzzi