[week2] FP라는 신세계

최민석·2021년 8월 15일
9

Programmers

목록 보기
3/5
post-thumbnail

2주차 주요 내용📄

이번 2주차 내용으로는 함수형 프로그래밍을 배웠다.

그동안 객체지향 프로그래밍만 접한 나에게는 새로웠고 신기했다.
이렇게 코드가 직관적이고 간단하게 보이다니 🙉...

그만큼 어려웠던 파트였고, 실전으로 다루기에는 아직 많이 부족하다.

그래서 이번주는 함수형 프로그래밍과 지연성/동시성에 대해 정리해보았다.

함수형 프로그래밍 vs 객체지향 프로그래밍


함수형 프로그래밍에 관한 내용을 살펴보면서 여러 의견이 나뉘었다.

"그건 함수형이 아니라 객체지향인데요?"라는 주제로 불타고 있는 내용을 봤다.

대부분의 내용들이 객체지향과 함수형은 두 가지를 나누어서
상호 배제적인 관계로 보는 것 같았다.

그렇지만 서로 직교하는 관계라는거를 인지해야 한다는 점!

서로 간의 장점을 활용해 다형성 + 참조 투명성 모든 걸 가진 완벽한 시스템을 만들 수 있다.

다형성은 비결합된 시스템을 만들어주어서 테스트가 쉽고, 유지보수와 개발이 편한 시스템이 된다.

참조 투명성은 시스템을 예상 가능하게 만들어 이해가 쉽고, 개발이 쉽고, 동시성도 해결이 된다.

결론은?

타이틀과 같이 함수형 vs 객체지향은 존재하지 않는다는 점. 모두 활용해서 유연하게 사용해야한다.


함수형 프로그래밍이란?

프로그래밍 패러다임 중 하나이며, 선언형 프로그래밍에 속한다.
함수를 기반으로 돌아가는 프로그래밍.

// 대입문을 사용하지 않고, 작은 문제를 하나씩 해결하기 위한 함수 작성
process(10, print(num));

특징?

다음과 같이 한 줄로 요약할 수 있다.

SideEffect 없는 순수 함수1급 객체로 간주하여
파라미터로 넘기거나 반환 값을 사용 할 수 있으며,
참조 투명성을 지킬 수 있다.

해당 강조된 명칭들을 가지고 다시 분석해보자.

SideEffect와 순수함수 특징


SideEffect란? 다음과 같은 변화가 발생하는 작업을 말한다.

  • 변수 값 변경
  • 자료 구조를 제자리 수정
  • 객체 필드 값 설정
  • 예외나 오류가 발생해 실행 중단
  • console 또는 File I/O 발생

이러한 SideEffect를 제거한 함수를 순수 함수라고 한다.

  • 함수 외부 데이터에 의존 X
  • 함수 외부 데이터를 변경 X

즉, 사이드이펙트를 없애고 함수끼리 조합성을 강조하는 패러다임이다.

순수함수 특징과 예시를 들어보았다.

  • 작성한 함수는 하나 이상의 인자를 받아야한다.
  • 반환 값이 반드시 존재해야 한다.
  • 함수 내에서 인자를 제외한 다른 변수를 사용해선 안된다.
  • 동일 입력/동일 출력이 보장된다.
  • 평가 시점이 중요하지 않다.
// map, reduce, filter는 함수형에 속한다.
// 기존 변수에 대한 사이드 이펙트로 없도록 구현하는 것이 원칙.

// map
const arr = [1,2,3,4,5];
const map = arr.map(function(x) { 
 return x * 2;
}); // [2,4,6,8,10]

// filter
const arr = [4, 15, 377, 395, 400, 1024, 3000];
const arr2 = arr.filter((v) => (v % 5 === 0));
console.log(arr2) // [15, 395, 400, 3000]

// reduce
let arr = [9, 2, 8, 5, 7];
let sum = arr.reduce((pre, val) => pre + val);
console.log(sum) // 31

지금까지는 함수형 프로그래밍에 대한 개념을 살펴봤으니,
우리는 함수형 자바스크립트 예시를 보면서 확인한다.


함수형 자바스크립트

평가

코드가 계산(Evalution)되어 값을 만드는 것을 말한다.

  • 1 + 2 = 3
  • (1 + 2) + 4 = 7
  • [1, 2+3] = [1, 5]
  • [1, 2, [3, 4]] = [1, 2, Array(2)]

일급

  • 값/변수/함수의 인자/함수의 결과를 사용할 수 있음.
const value = 10;
const add_value_10 = a => a + 10;
const result = add_value_10(value);
console.log(result); // 20;

일급 함수

  • 함수가 값으로 다뤄질 수 있다. (조합성 + 추상화 도구)
const add_5 = a => a + 5;
console.log(add_5); // a => a + 5;
console.log(add_5(5)); // 10

const func_1 = () => () => 1;
console.log(func_1()); // () => 1

const func_2 = func_1();
console.log(func_2); // () => 1
console.log(func_2()); // 1

고차 함수

  • 함수를 값을 다루는 함수

함수를 인자로 받는 예시

// 함수 로직을 보내서 내 입맛대로 개조가능 :)
const higher-order = func => func(1);
const add_2 = a => a + 2;
console.log(higher-order(add_2)); // 3
console.log(higher-order(a => a - 1)); // 0

함수를 만들어 Return하는 함수

  • 클로저(closer)를 활용한다.
const add_func = a => b => a + b;
const add_10 = add_func(10);
console.log(add_10(5)); // 15
console.log(add_10(10)); // 20
console.log(add_function(10)(5)); // 15 

이렇게 평가/일급/고차함수를 자바스크립트로 알아보았고,
제너레이터, 이터레이터/이터러블에 대해 알아보겠습니다.


이터러블/이터레이터/제너레이터

위를 살펴보기 전 간단하게 이터러블/이터레이터 프로토콜을 보자.

Iteration Protocol

  • 이터러블을 for..of, 전개 연산자 등 함께 동작하도록 한 규약을 말한다.
    • 프로토콜을 준수한 객체만이 for-of, 전개연산자를 사용할 수 있다는 점!!
  • Array, Set, Map은 프로토콜 규약에 준수한다.

자바스크립트 문법만 배우고 사용했던 나에게는 생소했던 내용이라 어려워보였지만 간단했다.

해당 개념은 함수형 자바스크립트에서의 핵심적인 내용이였다.

이터러블(Iterable)

이터레이터를 반환하는 [Symbol.iterator]()를 가진 값.

이터레이터(Iterator)

{ value, done } 객체를 반환하는 next()를 가진 값


const arr = [1, 2, 3];
let iterator = arr[Symbol.iterator]();
iterator.next(); // {value: 1, done:false}
iterator.next(); // {value: 2, done:false}
iterator.next(); // {value: 3, done:false}
iterator.next(); // {value: undefined, done:true}

제너레이터(Generator)

간단하다. 이터레이터이면서 이터러블을 생성하는 함수를 말한다.

function *go() {
	yield 1;
    yield 2;
    yield 3;
    return 100;
}

let iter = go();
iter.next(); // {value: 1, done: false}
iter.next(); // {value: 2, done: false}
iter.next(); // {value: 3, done: false}
iter.next(); // {value: 100, done: true}

가장 큰 특징으로는? 단, 한번만 순회 가능하다는 점..

여기까지가 이터러블/이터레이터/제너레이터의 기본적인 정리내용이였다.

이를 응용해 활용할 수 있는 개념들이 존재한다.

제너레이터/이터레이터를 활용한 지연성

이터러블 중심 프로그래밍에서의 지연 평가(Lazy Evalution)

예를 들어 큰 크기의 배열을 미리 만들어 제공하는 것이 아닌, 필요한 값만 생성해서 제공한다.

기존의 함수들은 엄격한 계산으로 값 전체를 반환하지만, 지연성을 활용한 구현은 필요한 값만 제공한다.

기존 함수 vs 지연 함수 예시

// 기존 함수
const arr = [0, 1, 2, 3, 4, 5];
const result = 
	arr.map(num => num + 10)
	.filter(num => num % 2)
	.slice(0, 2);
console.log(result); // [11, 13]

위와 같은 도표로 하나의 함수가 완전히 다 실행한 후에야 값이 전달되는 방식이다.

우리는 slice(0, 2) 를 통해 [4, 5]가 불필요한 값임을 알 수 있다. 즉, 계산 할 필요가 없다.


그러면 이터러블 방식의 지연 함수를 보자.

const arr = [0, 1, 2, 3, 4, 5]
const result = _.take(2,
	L.filter(num => num % 2,
   	L.map(num => num + 10, arr))
);
console.log(result) // [11, 13]

지연 평가 특징으로 흐름은 위에서 아래로 흐른다.

결과적으로 우리는 [4, 5] 요소 값을 생성하지 않고 진행했다.

지금은 비록 값이 적지만, 값이 큰 데이터를 다룬다면?
어마어마한 효율성을 지닌 함수가 완성된다.

1,000,000개의 요소 개수로 설정해 검사한 내용.
지연 평가가 압도적인 결과를 확인할 수 있다..

정말 간단하게 기존 map 함수에서 이터레이터와 제너레이터를 활용
map을 재구성 했을 뿐인데 효율적인 프로그래밍을 할 수 있었다.


2주차를 마치고😳

이번주는 아예 처음부터 배워보는 내용들이라서 흥미롭고 재밌었다. 쉽진 않았다.

함수형 프로그래밍에 대한 근본과 많은 예시들을 보여주신 2주차 강의들은
강사님의 노하우와 개념들이 담겨져있는 깊고도 재밌었던 시간이였다.

짧은 일주일이라는 기간 동안 많은 함수형의 개념과 예시를 보면서 멘탈이 나갈뻔했지만..

이렇게 간결한 코드를 작성할 수 있다는 매력은 학구열을 불타게하더라...!

이제야 자바스크립트에 대해 조-금 이해했다고 말할 수 있지 않을까?

🥺 week2 과제?

함수형 프로그래밍을 활용한 문제였는데 사실 처음에는 감도 오지 않았던 문제였다.

이미 명령형으로는 풀어보았던 문제라서 더 현타가 왔었던 과제였다. 그렇지만 재밌어..

답지는 제공되었지만 끝까지 보지 않고 마무리하는 방향으로 일단 제출은 무사히 마쳤다.(제출만)

약간 자존심의 문제였다. 지금 이걸 못 풀면 뭘 할 수 있을까 라는 걱정도 있었기도 했다.

결국에는 어느 정도 감을 잡고 진행을 했다는 내 모습이 스스로 기특했다.

아직 매운(?) 코드리뷰를 받지 않은 상태라 이렇게 여유로울 수 있는 것 같다... 다음주에는 더 열심히하기로..

매 주 자신감 짤을 이용해서 다음 주를 발판 삼아야겠다 :)


reference

profile
되돌아보며 성장합니다🔨

2개의 댓글

comment-user-thumbnail
2021년 8월 17일

한 주동안 고생 많으셨습니다!! ㅎㅎ 저희가 트렌딩 접수하죠!!! 🔥🔥🔥

1개의 답글