과거에 학습만 했던 함수형 프로그래밍:인프런 을 다시금 공부하면서 JS 기반 강의 내용을 python 적용하고 있다.
물론 python 도 좋은 FP 라이브러리가 있으나 해당 패키지들을 모두 샅샅히 찾아본 것은 아니라서 강의에서 들은 내용을 바탕으로 따로 작성해야하는 것들만 변경중.
(현재 사용중인 라이브러리는 toolz)
다만 기존 map, filter 등을 curry 하기 위해선 새로이 만들어서 사용하는게 편하긴 하다
@curry
def custom_map(func: Callable, iterable: iter):
res = []
for value in iterable:
res.append(func(value))
return res
@curry
def custom_filter(func: Callable, iterable: iter):
res = []
for value in iterable:
if func(value):
res.append(value)
return res
L.map = function *(func, iterable) {
for(const e of iterable)
yield func(e);
};
L.filter = function *(func, iterable) {
for(const e of iterable)
if(func(e))
yield e;
};
def lazy_filter(func: Callable, iterable: iter):
# yield from seq is equivalent to for i in seq: yield i
yield from (value for value in iterable if func(value))
def lazy_map(func: Callable, iterable: iter):
yield from (func(value) for value in iterable)
const reduce = (f, acc, iter) => {
if(!iter) {
iter = acc[Symbol.iterator]();
acc = iter.next().value;
}
for(const i of iter) {
acc = f(acc, i);
}
return acc;
}
def custom_reduce(func: Callable, acc=None, iterable: iter = []):
if not iterable:
iterable = acc[1:]
acc = acc[0]
for value in iterable:
acc = func(acc, value)
return acc
def test_lazy_funcs_should_fast_then_normal():
base_counts = 1000000
start = time.time()
res = go(
range(base_counts),
custom_map(lambda x: x + 10),
custom_filter(lambda x: x % 2 == 0),
custom_take(2),
)
end_time = time.time()
normal = end_time - start
assert res
start = time.time()
res = go(
range(base_counts),
lazy_map(lambda x: x + 10),
lazy_filter(lambda x: x % 2 == 0),
custom_take(2),
)
assert res
end = time.time()
lazy = end - start
print(f"Normal: {normal} sec, lazy: {lazy} sec")
assert normal > lazy
$pytest -k test_lazy_funcs_should_fast_then_normal -s
Normal: 0.26944684982299805 sec, lazy: 0.0002028942108154297 sec