시작하기에 앞서..
함수형 프로그래밍을 배우면서 프로그래밍을 새로 배운다고 생각해보자.
올바른 관점을 가진다면 올바른 생각을 하게 될 것이고, 개념이 어려워도 학습을 관두지 않을 것이다.
서두르지 말고 천천히 글을 보고, 코드를 이해하며, 사고를 정리하자.
가장 중요한 건 본인이 이해해야 한다는 것이다.
순수 함수
순수 함수는 굉장히 단순한, 그저 매개변수에 따라 계산이 이루어질뿐인 함수를 말한다.
달리 말하자면, 외부 상태를 변경 시키지 않고 동일한 매개변수가 주어졌을 때, 항상 같은 값을 리턴하는 함수를 의미한다.
이해를 위해 코드를 살펴보자.
1.
let z = 10;
function add(x, y) {
return x + y;
}
console.log(add(5,10)); // 15
console.log(add(5,10)); // 15
console.log(add(5,10)); // 15
초점을 두어야 할 부분은 z변수가 안쓰였다는 사실이 아니라, add함수가 z함수에 아무런 영향을 미치지 않았다는 것이다.
외부의 상태를 변경시키지 않는다.
그리고 add(5, 10)은 항상 15임을 알 수 있다. 이를 통해 알 수 있는 순수 함수의 특징은 다음과 같다.
같은 입력 값이 주어질 시, 항상 같은 값이 출력되어야 한다.
2.
function justTen() {
return 10;
}
console.log(justTen()); // 10
매개변수가 없는 순수 함수는 일을 안 하기 때문에 쓸모가 없다. 즉, 유용하지 않다는 말이다.
위 코드와 같은 경우 상수를 정의해 쓰는 편이 더 나을 것이다.
대부분의 유용한 순수 함수는 최소 한 개의 매개변수를 가진다.
3.
function addNoReturn(x, y) {
let z = x + y
}
이 함수는 아무것도 반환하지 않는다.
순수 함수는 자체 매개변수로만 동작을 해야 한다. 위 함수는 매개변수를 합치긴 하지만, 아무런 값도 반환하지 않기 때문에 쓸모가 없다.
유용한 모든 순수 함수는 반드시 무언가를 반환해야 한다.
4.
writeFile(fileName);
updateDatabaseTable(sqlCmd);
sendAjaxRequest(ajaxRequest);
openSocket(ipAddress);
위의 모든 함수들은 부작용을 가졌다. 저 함수들을 호출하게 되면, 파일과 데이터베이스의 테이블이 바뀌게 되고, 데이터를 서버로 전송하거나 소켓을 얻기 위해 OS를 호출하게 된다. 위의 함수들은 입력 값을 실행하는 것 외에 다른 작업들을 더 한다. 그리고 나서야 출력 값을 반환한다. 그러므로 이 함수들이 어떤 것을 반환할지 절대 예상할 수 없다.
순수 함수는 부작용이 없다.
자바스크립트, 자바, C#과 같은 명령형 프로그래밍 언어에서는 어디에서나 부작용이 존재한다.
함수형 프로그래밍을 통해 부작용을 제거할 순 없지만, 그 부작용을 제어할 순 있다.
왜냐하면 프로그램은 실제 세계와 맞닿는 부분이 존재하기 때문에 몇몇 부분은 비 순수 할 수밖에 없다.
목표는 비 순수한 코드를 최소한으로 줄이는 것이고, 그것들을 순수 함수로부터 도려내서 별도 공간에 분리시키는 것이다.
불변성
불변성은 변경 가능한 상태를 최대한 제거하려고 하는 특성이다.
let x = 1;
x = x + 1;
우리가 배운 수학에서는 x와 x+1은 절때 동일할 수 없다.
하지만 명령형(Imperative) 프로그래밍에서는 x변수에 1을 더해서 x에 값을 저장한다고 할 수 있다.
함수형 프로그래밍은 이러한 것이 불가능하다.
함수형 프로그래밍은 변수가 없다.
저장된 값은 여전히 변수로 불리지만, 변수에 한 번 값이 할당되었다면 그 값으로 계속 유지되어야 한다.
변수는 보통 지역변수로 사용되어 생명주기는 짧다.
함수형 프로그래밍은 반복을 하기 위해 재귀 함수를 사용한다.
함수형 프로그래밍은 반복하는 행위를 함에 있어서 for, while, do, repeat과 같은 반복문 구조를 사용하지 않는다.
// 1. 간단한 루프 구문
let acc = 0;
for (let i = 1; i <= 10; ++i)
acc += i;
console.log(acc); // 55
// 2. 루프 구문이나 변수 없이 (재귀)
function sumRange(start, end, acc) {
if (start > end)
return acc;
return sumRange(start + 1, end, acc + start)
}
console.log(sumRange(1, 10, 0)); // 55
2번과 같은 방식은 기존의 값을 수정하지 않는다. 대신에 기존의 값으로 새로운 값을 계산해서 사용한다.
자바스크립트에서는 재귀함수를 거의 찾아볼수 없다.
재귀함수로 구현하면 다소 난잡하고 재귀함수로 개발할 생각을 해본적이 없기 때문일지도 모른다.
for을 이용한 반복문이 훨씬 더 쉽다고 생각할 수도 있다.
논쟁의 여지가 있고, 친숙함에 대한 문제이기도 하지만, 비 재귀 함수 반복은 "변함(Mutability)"을 요구한다.
그래서 좋지 않다.
불변성은 코드를 간단하게 만들어주고 안전하게 해준다.
참고하면 좋은 글
'Programming > Javascript' 카테고리의 다른 글
Javscript의 Math.random과 정규분포에 대해 (0) | 2022.01.28 |
---|---|
OverRiding(오버라이딩)과 OverLoading(오버로딩) 간단 정리 (0) | 2021.06.05 |
ES6 Class (0) | 2020.04.23 |
한 줄짜리 if 문, for 문 그리고 함수 (0) | 2020.04.22 |
객체 리터럴 사용 시, 값이 undifined라고 뜬다면.. (0) | 2020.04.22 |