지연성2

jodmsoluth·2020년 3월 14일
0

함수형프로그래밍

목록 보기
4/17

결과를 만드는 함수 reduce, take

// map, filter는 지연성을 가진다. 중첩해서 사용하여 iterator를 만들어 가는 함수
// reduce는 시작점을 알리는 함수, iterator의 값들을 꺼내서 깨트리는 함수, 지연성을 가지기 보다는 연산이 이루어 진다.
// take는 몇개로 떨어질지 모르는 배열에서 특정 개수의 배열로 축약하고 완성을 지어버리는 함수, 지연성을 가지는 것 보다는 take한 시점에 연산이 이루어 진다.

reduce, join

// 예제) queryStr 함수
const queryStr = obj => go(
  obj,
  Object.entries,
  map(([k, v]) => `${k}=${v}`),
  reduce((a, b) => `${a}&{b}`)
);
console.log(queryStr({ limit: 10, offset: 10, type: 'notice' }));

// output : limit=10&offset=10&type=notice
// 예제) Array.prototype.join 보다 다형성 높은 join

const join = curry((sep=',', iter) => reduce((a, b) => `${a}${sep}${b}`, iter);

const queryStr = obj => go(
  obj,
  Object.entries,
  map(([k, v]) => `${k}=${v}`),
  join('&');
);

console.log(queryStr({ limit: 10, offset: 10, type: 'notice' }));

// output : limit=10&offset=10&type=notice

// 위에 코드와 달리 지연성을 가지는 join

L.entries = function *(obj) {
  for (const k in obj) yield [k, obj[k]];
}

const queryStr = obj => pipe(
  L.entries(obj),
  L.map(([k, v]) => `${k}=${v}`),
  join('&');
);

console.log(queryStr({ limit: 10, offset: 10, type: 'notice' }));
// 지연성을 가지는 join
// output : limit=10&offset=10&type=notice

take, find

const users = [
  { age: 32 },
  { age: 31 },
  { age: 37 },
  { age: 28 },
  { age: 25 },
  { age: 32 },
  { age: 31 },
  { age: 37 }
];

const find = curry((f, iter) => go(
  iter,
  L.filter(f), // find 함수에 지연성을 준다.
  take(1),
  ([a]) => a
));

log(find(u => u.age < 30)(users));
 
go(users,
   L.map(u => u.age),
   find(n => n < 30),
   console.log);

L.map, L.filter로 map과 filter 만들기

L.map = curry(function *(f, iter) {
  for (const a of iter) {
    yield f(a);
  }
});

L.filter = curry(function *(f, iter) {
  for (const a of iter) {
    if(f(a)) yield a;
  }
});

const takeAll = take(Infinity);

const map = curry(pipe(L.map, takeAll));
const filter = curry(pipe(L.filter, takeAll));

L.flatten, flatten

// 이런 값을 [[1, 2], 3, 4, [5, 6], [7, 8, 9]]
// [...[1, 2], 3, 4, ...[5, 6], ...[7, 8, 9]]
// 이렇게 동작하고 지연성을 가진다.

const isIterable = a => a && a[Symbol.iterator];

L.flatten = function *(iter) {
  for (const a of iter) {
    if(isIterable(a)) {
      /*
      for (const b of a)
        yield b; */
      yield *a
    }
    else yield a;
  }
}

const it = L.flatten([...[1, 2], 3, 4, ...[5, 6], ...[7, 8, 9]])
console.log([...it])

// ---

const takeAll = take(Infinity)
const flatten = pipe(L.flatten, takeAll);
console.log(flatten([...[1, 2], 3, 4, ...[5, 6], ...[7, 8, 9]])

tip) yield *iterable = for (const val of iterable) yield val;

L.flatMap flatMap

// 자바스크립트가 기본적으로 지연적을 동작하지 않기 때문에 만들어진 함수들
// 지연적으로 동작 하는 L.flatten 후 지연적인 동작을 하는 L.Map을 한 것이 L.flatMap

L.flatMap = curry(pipe(L.map, L.flatten));
const flatMap = curry(pipe(L.map, L.flatten, takeAll));
const it = L.flatMap(a => a, [[1, 2], [3, 4], [5, 6, 7]]
console.log([...it]);

console.log(L.flatMap(L.range, map(a => a + 1, [1, 2, 3]));

2차원 배열 다루기

const arr = [
  [1, 2],
  [3, 4, 5],
  [6, 7, 8],
  [9, 10]
];

go(arr,
   L.flatten,
   L.filter(a => a % 2),
   L.map(a => a * a),
   take(3),
   reduce(add),
   console.log);

이터러블 중심 프로그래밍 실무적인 코드

var users = [
  { name : 'a', age: 21, family: [
    { name: 'a1' age: 53 }, { name: 'a2', age: 47 }, { name: 'a3' age: 16 }, { name: 'a4', age: 15 }] },
  { name : 'b', age: 21, family: [
    { name: 'b1' age: 53 }, { name: 'b2', age: 47 }, { name: 'b3' age: 16 }, { name: 'b4', age: 15 }] },
  { name : 'c', age: 21, family: [
    { name: 'c1' age: 53 }, { name: 'c2', age: 47 }, { name: 'c3' age: 16 }, { name: 'c4', age: 15 }] },
  { name : 'd', age: 21, family: [
    { name: 'd1' age: 53 }, { name: 'd2', age: 47 }, { name: 'd3' age: 16 }, { name: 'd4', age: 15 }] }
];

go(users,
   // L.map(u => u.family), // 가족을 뽑고
   // L.flatten, // 가족을 펼치고
   L.flatMap(u => u.family),
   L.filter(u => u.age < 20), // 나이가 20 미만을 추출해서
   L.map( u => u.name), // 이름만 가져온다.
   take(4), // 4명의 이름만 가져온다.
   console.log);
profile
풀스택이 되고 싶은 주니어 웹 개발자입니다.

0개의 댓글