함수형프로그래밍 - 지연성

ZeroJun·2022년 5월 9일
0

함수형프로그래밍

목록 보기
4/5

range와 L.range구현

/* eslint-disable */
import { log, curry, map, filter, reduce, go, pipe } from '../lib/fx.js';

/* 지연평가 */
const add = (a, b) => a + b;

// range
const range = l => {
    let i = -1;
    let result = [];
    while (++i < l) {
        log(i, 'range');
        result.push(i);
    }
    return result;
}
var list = range(4); // range를 호출했을 때, 즉시 배열로 평가된다.
log(list); // [0, 1, 2, 3, 4]
log(reduce(add, list)); //6

// 느긋한 L.range
const L = {};
L.range = function* (l) {
    let i = -1;
    while (++i < l) {
        log(i, 'L.range');
        yield i;
    }
}

var list = L.range(4); // range를 호출했을 때, 아직 평가되지 않는다.
log(list); // L.range : Generator
log(reduce(add, list)); // array를 만들지 않고, 하나씩 값을 꺼내게 된다.

range와 L.range의 성능 테스트

const test = (name, time, f) => {
    console.time(name);
    while (time--) f();
    console.timeEnd(name);
}

test('L.range', 1, () => reduce(add, L.range(10000000))); // 200ms
test('range', 1, () => reduce(add, range(10000000))); // 250ms

take

const take = curry((l, iter) => {
  let res = [];
  for (const a of iter) {
    res.push(a);
    if (res.length == l) return res;
  }
  return res;
})

console.time('기본');
go(
    range(10000),
    take(5), // 5개만 꺼내온다.
    reduce(add),
    log
)
console.timeEnd('기본');

console.time('지연');
go(
    L.range(10000),
    take(5), // 5개만 꺼내온다.
    reduce(add),
    log
)

L.map, L.filter구현

L.range = function* (l) {
  let i = -1;
  while (++i < l) {
    yield i;
  }
}

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

L.map, L.filter를 평가하여 만드는 map, filter

const takeAll = take(Infinity);

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

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

이는 결국 결과를 만드는 take에 의해 이터레이터가 평가되면서 원래의 map, filter과 같은 동작을 하게 된다.

그 밖의 유용한 함수

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

export const flatten = curry(pipe(L.flatten, takeAll));

L.deepflat = function* f(iter) {
  for (const a of iter) {
    if (isIterable(a)) yield* f(a)
    else yield a;
  }
}

L.flatMap = curry(pipe(L.map, L.flatten));

export const flatMap = curry(pipe(L.map, flatten));

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

0개의 댓글