난이도 : 초급
Shantanu Bhattacharya, Chief consultant, Siemens Information Systems Limited
2007 년 3 월 27 일
함수 프로그래밍(Functional programming) 또는 선언적 프로그래밍(Declarative programming)은 매우 강력한 프로그래밍 방식이고, 소프트웨어 업계에서 대중성을 얻어가고 있습니다. 이 글에서는 함수 프로그래밍의 개념을 설명하고, 그러한 개념들을 효과적으로 사용할 수 있는 실질적인 예제들도 제공합니다. 함수 프로그래밍의 구조와 기능들을 JavaScript™에 적용하여 고급 코드를 작성하는 방법을 설명합니다.
함수 프로그래밍 언어는 꽤 오랫동안 학계에서 사용되었지만, 비교적 광범위한 툴들과 유용한 라이브러리들을 갖춘 적이 없었다고 평가할 수 있다. .NET 플랫폼에 Haskell이 도입되면서, 함수 프로그래밍은 보다 대중적이 되었고, C++과 JavaScript 같은 일부 전통적인 프로그래밍 언어들은 함수 프로그래밍의 구조와 기능을 사용하고 있다. 많은 경우, JavaScript에서의 반복되는 코드는 추한 코딩으로 치부되었다. 함수 프로그래밍을 사용한다면 이 모든 문제들을 피할 수 있다. 또한, 함수 프로그래밍 스타일로 고급스러운 콜백(callback)을 작성할 수도 있다.
|
함수 프로그래밍은 매우 다른 방식으로 프로그램들을 구성하기 때문에, 명령 패러다임에 익숙한 프로그래머들은 이를 배우기가 어렵다. 이 글에서는, JavaScript에서 함수 스타일로 고급 코드를 작성하는 방법을 설명하겠다.
|
많은 개발자들은 "어떻게"를 기술함으로써 문제를 해결하는 방식을 지정한 언어로 코딩 하는 방법을 알고 있다. 예를 들어, 하나의 팩토리얼(factorial)을 계산하는 함수를 코딩 하려면, 루프를 코딩 하거나 회귀를 사용하여 모든 숫자들의 결과를 찾는 프로그램을 기술한다. 두 경우 모두, 계산 절차는 프로그램에 상세히 나와 있다. Listing 1은 이러한 팩토리얼에 대한 C 코드이다.
int factorial (int n) { if (n <= 0) return 1; else return n * factorial (n-1); } |
문제를 풀기 위해 절차를 정의하기 때문에, 이 같은 언어들을 절차 프로그래밍(procedural programming) 언어라고 한다. 함수 프로그래밍은 이러한 개념과는 다르다. 함수 프로그래밍에서는 그 문제의 "무엇"을 기술해야 한다. 함수 프로그래밍 언어는 선언적(declarative) 프로그래밍이라고 불린다. 팩토리얼을 계산하는 같은 프로그램은 최대 n까지 모든 숫자들의 결과로 작성된다. 팩토리얼에 대한 전형적인 함수 프로그램은 Listing 2의 예제와 같다.
factorial n, where n <= 0 := 1 factorial n := foldr * 1 take n [1..] |
두 번째 문은 1부터(take n [1..]) 시작하는 첫 번째 n numbers starting from 1 (take n [1..]
숫자들을 취하라고 명령한 다음, 아이디가 1인 결과를 찾는다. 이 정의는 이전 경우에서처럼 루프나 재귀적 호출이 없다. 이것은 팩토리얼 함수의 수학적 정의와 같다. 일단 라이브러리 함수(take
와 foldr
)와 표기법(list notation [ ]
)을 알면, 코딩이 매우 쉬워지고 가독성도 높아진다.
|
역사적으로, 함수 프로그래밍 언어는 여러 가지 이유 때문에 대중화 되지 못했다. 하지만 최근에, 이러한 언어들 중 일부가 컴퓨터 업계에 진입하기 시작하다. 한 가지 예가 .NET 플랫폼의 Haskell이다. 다른 경우로는, 기존 언어들 중 일부가 함수 프로그래밍 언어에서 개념을 빌린 경우이다. Iterator와 continuation이 C++ 의 구현에 나타나고, JavaScript에는 일부 함수 구조가 제공된다지만, 함수 구조를 빌린다고 해서, 언어의 전체적인 프로그래밍 패러다임이 변하지는 않는다. JavaScript는 함수 구조를 추가했다고 해서 함수 프로그래밍 언어가 되지는 않는다는 의미이다.
이제부터는 JavaScript의 다양한 함수적 구조의 장점들에 대해 설명하고, 일상적인 코딩 작업에 이들을 사용하는 방법을 설명하겠다. 몇 가지 기본적인 기능부터 시작해 보겠다.
JavaScript에서, 익명 함수 또는 이름이 없는 함수들을 작성할 수 있다. 왜 이것이 필요한가? 계속 읽어가다 보면 알게 될 것이지만, 여러분은 우선 이들을 작성하는 방법을 배워야 한다. 다음과 같은 JavaScript 함수를 보자.
Listing 3. 일반적인 함수
function sum(x,y,z) { return (x+y+z); } |
이에 상응하는 익명 함수는 다음과 같다.
Listing 4. 익명 함수
function(x,y,z) { return (x+y+z); } |
이것을 사용하려면, 다음과 같이 작성한다.
var sum = function(x,y,z) { return (x+y+z); }(1,2,3); alert(sum); |
또한, 함수들을 값으로서 사용할 수도 있다. 변수와 함수들도 가질 수 있는데 이 값들은 이들에게 할당된 값으로서 마지막 예제에서, 다음과 같이 할 수 있다.
Listing 6. 함수 할당 사용하기
var sum = function(x,y,z) { return (x+y+z); } alert(sum(1,2,3)); |
위 Listing 6의 예제에서, 변수 합은 함수 정의로 할당된다. 따라서, 합은 함수이고, 원하는 어떤 곳에서나 호출된다.
JavaScript로는 두 가지 방식으로 함수를 호출할 수 있다. (7과 8)
alert (“Hello, World!"); |
또는
(alert) (“Hello, World!"); |
따라서, 다음과 같이 작성할 수도 있다.
( function(x,y,z) { return (x+y+z) } ) (1, 2, 3); |
괄호 안에 함수 식을 작성하고, 인자를 전달하여 이들을 계산되도록 한다. Listing 8 예제에서는 함수 이름이 괄호 안에 직접 인클로즈 되지만, Listing 9에서처럼 꼭 그렇게 할 필요는 없다.
또한 함수들을 인자로서 다른 함수들에 전달할 수 있다. 이는 새로운 개념은 아니지만, 다음 예제들처럼 광범위하게 사용될 수 있다. Listing 10처럼, 함수 인자들을 전달할 수 있다.
var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); }; var sum = function(x,y,z) { return x+y+z; }; alert( passFunAndApply(sum,3,4,5) ); // 12 |
마지막 alert 문의 실행은 12라는 값을 만들어 낸다.
이전 섹션에서는 함수 스타일을 사용하는 프로그래밍 개념을 설명했다. 이 예제들은 이 모든 개념을 다 다루는 것도 아니며, 중요한 순서대로 나열한 것도 아니지만, 이 논의와 관련 있는 개념들이다. JavaScript의 함수 스타일로 요약하자면,
이 섹션에서는 이러한 개념들을 효과적으로 사용하여 JavaScript로 고급 코드를 작성하는 방법을 예제를 통해 설명했다. (JavaScript의 함수 스타일을 사용해서, 이 글에서는 설명하지 않은 다른 많은 작업들도 수행할 수 있다.)
function (x,y) { return x.date – y.date; } |
필요한 함수를 얻으려면, Listing 12의 예제를 사용한다.
arr.sort( function (x,y) { return x.date – y.date; } ); |
여기에서 arr는 유형 배열의 객체이며, 이것은 각각의 날짜 별로 arr의 모든 객체들을 분류할 것이다. 비교 함수와 이것의 정의는 sort 함수로 전달되어 sort 연산을 완료한다. 이 함수를 통해서,
qsort
함수와 비슷하다. Listing 13의 코딩 스타일은 배열에서 동적인 HTML을 생성하는데 사용된다.
var str=' '; for (var i=0;i<arr.length;i++) { var element=arr[i]; str+=... HTML generation code... } document.write(str); |
이 코드를 Listing 14의 코드로 대체할 수 있다.
Array.prototype.fold=function(templateFn) { var len=this.length; var str=' '; for (var i=0 ; i<len ; i++) str+=templateFn(this[i]); return str; } function templateInstance(element) { return ... HTML generation code ... } document.write(arr.fold(templateInstance)); |
필자는 Array
유형의 prototype 프로퍼티를 사용하여 새로운 함수를 정의했다. 여러분은 이제 나중에 정의된 어떤 배열에서나 이 함수를 사용할 수 있다.
window.setTimeout
함수를 사용하게 될 것이다. 첫 번째 매개변수는 두 번째 매개변수에서 지시된 대로 밀리초 후에 호출된다. Listing 15는 이를 수행하는 한 가지 방법이다.window.setTimeout(function(){alert(‘First!’);alert(‘Second!’);}, 5000); |
Listing 16은 이를 수행하는 보다 고급 방식이다.
Function.prototype.sequence=function(g) { var f=this; return function() { f();g(); } }; function alertFrst() { alert(‘First!’); } function alertSec() { alert(‘Second!’); } setTimeout( alertFrst.sequence(alertSec), 5000); |
이벤트를 처리하면서, 다른 것을 호출한 후에 하나의 콜백을 호출하기 원한다면 Listing 16의 코드를 사용할 수 있다. 아마도 이것은 여러분에게 잘 맞을 것이다.
|
|
많은 영역에서, 여러분은 함수 프로그래밍 개념을 JavaScript에 적용하여 보다 고급스러운 방식으로 작업을 수행할 수 있으며, 이 글에서 소개한 예제들은 단면만을 보여준 것이다. 함수 프로그래밍에 맞는 시나리오를 찾아냈다면 그 개념을 적용해 보고 이해해 보기 바란다.
Shantanu Bhattacharya는 애플리케이션 소프트웨어, 시스템 통합, 헬쓰케어용 아키텍처를 설계 및 구현했다. 이 외에도, 네트워킹 소프트웨어, 보안 소프트웨어, 인도의 첫 번째 슈퍼컴퓨터용 파일 시스템, Real Time Software for the Indian Missile Program도 설계했다. 현재 인도 방갈로르 지방에서 보건 분야에서 아키텍트로 활동하고 있다. |