개발/Java Script

[JS] 함수형 프로그래밍이란 - 스터디 1주차

hojak99 2017. 10. 18. 15:21

1주차

함수형 패러다임 개념

함수형 프로그래밍이란

  • 순수 함수를 지향하는 프로그래밍 패러다임
  • 변경 가능한 상태를 불변상태로 만들어 부작용 없애도록 프로그래밍

왜 Java Script 에서도 함수형 프로그래밍이 가능한 것일까?

구글링과 아는 지식으로 생각해보면 Java Script 에서의 함수는 1급 계층이라고 할 수 있는 것 같다.
- 함수를 다른 함수에 인자로 넘길 수 있음
- 함수 안에서 함수로 반환 가능

함수형 프로그래밍 기법 함수형 프로그래밍 기법이라고 해서 너무 어렵게 생각할 필요가 없는 것 같다. 그냥 조금 어렵다고 생각하면 된다.

함수형 프로그래밍은 기존에 객체지향 프로그래밍이나 절차지향 프로그래밍에서 사용했던 for문을 그저 재귀함수로 그 역할을 대신할 수 있도록 프로그래밍 한다고 생각하면 될 것 같다.

그렇다면 함수형 프로그래밍이 지향하는 순수함수에 대한 예제를 보면서 한 번 이해해보쟈


var temp = 10;
function add (x, y) {
    return x+y;
}

위에 있는 코드는 우선 순수함수다. 인자로 받은 x, y를 값 변경을 하지 않고 더한 값을 바로 반환시켜주며 함수 스코프 내에 있는 다른 변수들을 사용하지 않았기 때문에 순수함수라고 할 수 있다.

그렇다면 다음의 코드에 대해서 순수함수인지 아닌지에 대해서 생각해보도록 하자.


function add(x, y){ 
    var z = x + y;
    return z;
}

이 부분에 대해서 같이 스터디하는 분께 여쭤보았는데 순수함수가 맞을 수도 있고 아닐 수도 있다고 하셔서 나도 잘 모르겠다. 이 부분에 대해서는 같이 이야기하면서 알아봐야 할 것 같다.

2017.10.14. 여기서 그저 순수히 z를 리턴하고 있는 코드이기 때문에 순수함수라고 말할 수 있다고 한다.


다시 본론으로 돌아와 filter 함수를 이용해서 순수함수를 만들어보자.


var arr = [0,1,2,3,4,5];
var getFive = function(i) {
    return i === 5;
}

var result = function(array, func) {
    return array.filter(func);
}

result(arr, getFive);

우선 result는 순수함수이다. 아까 위에서 말했 듯이 인자값들로만 프로그래밍 되어 있기 떄문이다. 만약 다음과 같은 코드가 된다면 result 함수는 더 이상 순수함수가 아닐 것이다.


var result = function(array) {
    return array.filter(getFive);
}

왜냐하면 함수 스코프 외에 있는 함수를 사용했기 때문이다.

이제 순수함수를 이용해 함수형 프로그래밍한 예제를 살펴보자.


var sum = 0;

function add(sum, count) {
    sum += count;

    if(count > 0) {
        return add(sum, count -1);
    }else {
        return sum;
    }

    add(sum, 10);
}

제일 처음 말했던 것처럼 add() 함수에서는 for문 대신 재귀함수로 그 역할을 했다. 그래서 코드를 볼 때 좀 더 명확하고 우리가 쉽게 예상할 수 있는 코드가 되었다.

옛날에 C언어 배울 때는 재귀함수는 왠만하면 사용하지 말라고 했었는데 지금은 오히려 재귀함수를 사용해야 하니 새로운 프로그래밍 패러다임을 배우려면 기존에 있는 생각을 버려야 한다는 느낌을 받았다.

마지막으로 reduce 함수를 이용해 위의 코드를 더 진화시켜보도록 하겠다.


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

arr.reduce(function(prev, cur) {
    return prev + cur;
});

이런 식으로 무척이나 쉽고, 간단하게 재귀함수를 사용하지 않고도 코드를 짤 수 있다. 여기서 reduce 함수는 앞으로 많이 사용할 함수가 분명하기 때문에 항상 기억하고 있어야 한다고 생각된다.

reduce 함수에서 prev, cur 은 그냥 쉽게 생각해 이렇게 생각하면 된다.

위와 같이 reduce 함수가 작동하게 된다.

prevcurresult
1123
2336
36410
410515
515621
621728
728836
836945
9451055








위에 내용은 이제 발표하기 전에 내가 공부한 것들을 정리해 놓은 내용인데 좀 더 설명을 해야할 것 같아서 글을 쓴다.


우선 "변경 가능한 상태" 라는 것은 어떤 것을 뜻하는 걸까?


우선 Java 와는 다르게 Java Script 에서 변수는 Immutability 하다. 그래서 Java 처럼 같이 변경되는 것이 아니라 새로운 메모리에 그 값을 저장하는 것이다. 그래서 Java Script 에서 변수를 Immutability 하다가 하는 것이다. 


하여튼, 변경 가능하지 못하도록 하는 프로그래밍이라고도 할 수 있다. 변경 가능하지 못하므로 부작용이 나타나지 않는 것이다. 





여기서 말하는 "부작용" 이라는 무엇을 말할까? 


부작용은 예를 들어, 동시성 프로그래밍, 병렬 프로그래밍을 할 때 생겨나는 부작용을 말한다. 이 부분은 예전에 쓰레드에 관해서 공부했던 건데 예를 들어보겠다. 아래의 코드를 확인해보자.


void testMethod(String a, String b) { ----------- 1    int strLength = a.length() + b.length(); ----------- 2

if(strLength != 10) { ----------- 3

a = null; ----------- 4

b = null; ----------- 5

}

}


우선 코드가 좀 이상하긴 한데 이해하기 쉬운 코드이다. 


만약 스레드를 2개를 생성하고 각각의 A, B 라는 스레드에서 testMethod() 라는 메소드를 실행했다고 할 때, synchronized 키워드가 없으므로 먼저 메소드를 실행할 스레드에 대해선 알 수 없지만 B라는 스레드에서 먼저 메소드를 실행시켰다고 하자.


B라는 스레드에서 2번째 코드를 처리하고 4 번째 코드에 도달했다. 물론 여기서 strLength는 10 이 아니라는 가정이다. 


B 스레드 -> 5번 째 코드 진입 중

A 스레드 -> 2번 째 코드 진입 중


이 때, a는 null이다. B라는 스레드에서 5번 째 코드를 처리한다면 b도 널이 될 것이다. 그런데 A 스레드에서 null을 가지는 변수를 가지고 작업을 하려고 한다면 아마 프로그램은 터질 것이다. 바로 이것을 부작용이라고 한다.


Java 에선 이 부작용을 없애려 synchronized 키워드를 사용하지만 이렇게 되면 성능 상에 문제가 생긴다. 그래서 성능 상에 문제가 발생할 염려 없이 변경 불가능한 상태로 만들어 프로그래밍을 한다는 것이다.




반응형