|
|
|
난이도 : 초급
Shantanu Bhattacharya, Chief consultant, Siemens Information Systems Limited
2007 년 3 월 27 일
함수 프로그래밍(Functional programming) 또는 선언적 프로그래밍(Declarative programming)은 매우 강력한 프로그래밍 방식이고, 소프트웨어 업계에서 대중성을 얻어가고 있습니다. 이 글에서는 함수 프로그래밍의 개념을 설명하고, 그러한 개념들을 효과적으로 사용할 수 있는 실질적인 예제들도 제공합니다. 함수 프로그래밍의 구조와 기능들을 xxJavaScript™에 적용하여 고급 코드를 작성하는 방법을 설명합니다.
머리말
함수 프로그래밍 언어는 꽤 오랫동안 학계에서 사용되었지만, 비교적 광범위한 툴들과 유용한 라이브러리들을 갖춘 적이 없었다고 평가할 수 있다. .NET 플랫폼에 Haskell이 도입되면서, 함수 프로그래밍은 보다 대중적이 되었고, C++과 xxJavaScript 같은 일부 전통적인 프로그래밍 언어들은 함수 프로그래밍의 구조와 기능을 사용하고 있다. 많은 경우, xxJavaScript에서의 반복되는 코드는 추한 코딩으로 치부되었다. 함수 프로그래밍을 사용한다면 이 모든 문제들을 피할 수 있다. 또한, 함수 프로그래밍 스타일로 고급스러운 콜백(callback)을 작성할 수도 있다.
|
함수 프로그래밍(Functional programming)
함수 프로그래밍은 중간 결과를 저장하는 임시 변수들을 사용하지 않고, 프로그램에 대한 입력들에 대해서 수행될 연산들만을 기술한다. 중요한 것은 "어떻게(how)" 보다는 "무엇(what)과 왜(why)"에 집중한다는 점이다. 순차적 명령어의 실행을 강조하는 절차 프로그래밍(procedural programming)과는 대조적으로 상태 머신들의 구현 보다는 함수들의 정의를 강조한다.
대규모 지식 관리 애플리케이션은 개발 과정을 단순화 하는 함수 프로그래밍 스타일을 사용하여 큰 효과를 볼 수 있다. | |
함수 프로그래밍은 매우 다른 방식으로 프로그램들을 구성하기 때문에, 명령 패러다임에 익숙한 프로그래머들은 이를 배우기가 어렵다. 이 글에서는, xxJavaScript에서 함수 스타일로 고급 코드를 작성하는 방법을 설명하겠다.
- 함수 프로그래밍 개념: 익명 함수(anonymous function), 다양한 함수 호출 방식들, 함수를 인자로서 다른 함수들로 전달하는 방법.
- 함수 개념의 사용과 예제: 배열 정렬 확장. 동적 HTML 생성을 위한 고급 코드, 함수의 시퀀스의 적용
함수 프로그래밍 개념
많은 개발자들은 "어떻게"를 기술함으로써 문제를 해결하는 방식을 지정한 언어로 코딩 하는 방법을 알고 있다. 예를 들어, 하나의 팩토리얼(factorial)을 계산하는 함수를 코딩 하려면, 루프를 코딩 하거나 회귀를 사용하여 모든 숫자들의 결과를 찾는 프로그램을 기술한다. 두 경우 모두, 계산 절차는 프로그램에 상세히 나와 있다. Listing 1은 이러한 팩토리얼에 대한 C 코드이다. Listing 1. 절차 스타일에서의 팩토리얼
int factorial (int n)
{
if (n <= 0)
return 1;
else
return n * factorial (n-1);
}
|
문제를 풀기 위해 절차를 정의하기 때문에, 이 같은 언어들을 절차 프로그래밍(procedural programming) 언어라고 한다. 함수 프로그래밍은 이러한 개념과는 다르다. 함수 프로그래밍에서는 그 문제의 "무엇"을 기술해야 한다. 함수 프로그래밍 언어는 선언적(declarative) 프로그래밍이라고 불린다. 팩토리얼을 계산하는 같은 프로그램은 최대 n까지 모든 숫자들의 결과로 작성된다. 팩토리얼에 대한 전형적인 함수 프로그램은 Listing 2의 예제와 같다. 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 [ ] )을 알면, 코딩이 매우 쉬워지고 가독성도 높아진다.
|
Miranda 코드의 단 세 줄로, 매개변수에 따라서, 너비 우선(breadth-first)또는 깊이 우선(depth-first) 트래버스를 사용하여 n-ary의 각 엘리먼트를 처리하는 루틴을 작성할 수 있다. | |
역사적으로, 함수 프로그래밍 언어는 여러 가지 이유 때문에 대중화 되지 못했다. 하지만 최근에, 이러한 언어들 중 일부가 컴퓨터 업계에 진입하기 시작하다. 한 가지 예가 .NET 플랫폼의 Haskell이다. 다른 경우로는, 기존 언어들 중 일부가 함수 프로그래밍 언어에서 개념을 빌린 경우이다. Iterator와 continuation이 C++ 의 구현에 나타나고, xxJavaScript에는 일부 함수 구조가 제공된다지만, 함수 구조를 빌린다고 해서, 언어의 전체적인 프로그래밍 패러다임이 변하지는 않는다. xxJavaScript는 함수 구조를 추가했다고 해서 함수 프로그래밍 언어가 되지는 않는다는 의미이다.
이제부터는 xxJavaScript의 다양한 함수적 구조의 장점들에 대해 설명하고, 일상적인 코딩 작업에 이들을 사용하는 방법을 설명하겠다. 몇 가지 기본적인 기능부터 시작해 보겠다.
익명 함수
xxJavaScript에서, 익명 함수 또는 이름이 없는 함수들을 작성할 수 있다. 왜 이것이 필요한가? 계속 읽어가다 보면 알게 될 것이지만, 여러분은 우선 이들을 작성하는 방법을 배워야 한다. 다음과 같은 xxJavaScript 함수를 보자. Listing 3. 일반적인 함수
function sum(x,y,z) {
return (x+y+z);
}
|
이에 상응하는 익명 함수는 다음과 같다. Listing 4. 익명 함수
function(x,y,z) {
return (x+y+z);
}
|
이것을 사용하려면, 다음과 같이 작성한다. Listing 5. 익명의 함수 적용하기
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의 예제에서, 변수 합은 함수 정의로 할당된다. 따라서, 합은 함수이고, 원하는 어떤 곳에서나 호출된다.
함수를 호출하는 다양한 방식
xxJavaScript로는 두 가지 방식으로 함수를 호출할 수 있다. (7과 8) Listing 7. 일반적인 함수 적용
alert (“Hello, World!");
|
또는 Listing 8. 함수를 식으로 사용하기
(alert) (“Hello, World!");
|
따라서, 다음과 같이 작성할 수도 있다. Listing 9. 정의 후에 바로 함수 적용
( function(x,y,z) { return (x+y+z) } ) (1, 2, 3);
|
괄호 안에 함수 식을 작성하고, 인자를 전달하여 이들을 계산되도록 한다. Listing 8 예제에서는 함수 이름이 괄호 안에 직접 인클로즈 되지만, Listing 9에서처럼 꼭 그렇게 할 필요는 없다.
함수를 인자로서 다른 함수에 전달하기
또한 함수들을 인자로서 다른 함수들에 전달할 수 있다. 이는 새로운 개념은 아니지만, 다음 예제들처럼 광범위하게 사용될 수 있다. Listing 10처럼, 함수 인자들을 전달할 수 있다. 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라는 값을 만들어 낸다.
함수적 개념 사용하기
이전 섹션에서는 함수 스타일을 사용하는 프로그래밍 개념을 설명했다. 이 예제들은 이 모든 개념을 다 다루는 것도 아니며, 중요한 순서대로 나열한 것도 아니지만, 이 논의와 관련 있는 개념들이다. xxJavaScript의 함수 스타일로 요약하자면,
- 함수들이 늘 이름을 갖고 있을 필요는 없다.
- 함수들은 다른 값들처럼 변수들로 할당될 수 있다.
- 함수 식은 다음에 적용될 수 있도록 괄호 안에 작성 및 인클로즈 될 수 있다.
- 함수들은 인자로서 다른 함수들에 전달될 수 있다.
이 섹션에서는 이러한 개념들을 효과적으로 사용하여 xxJavaScript로 고급 코드를 작성하는 방법을 예제를 통해 설명했다. (xxJavaScript의 함수 스타일을 사용해서, 이 글에서는 설명하지 않은 다른 많은 작업들도 수행할 수 있다.)
- 배열 소트 확장하기
- 날짜에 따라 배열(array) 엘리먼트들을 분류할 수 있는 sort 메소드를 작성해 보자. 이것을 xxJavaScript로 작성하기는 매우 간단하다. 배열 객체들의 sort 메소드는 Listing 11과 같은 비교 함수인 매개변수를 취한다.
Listing 11. 비교 함수
function (x,y) {
return x.date – y.date;
}
|
필요한 함수를 얻으려면, Listing 12의 예제를 사용한다. Listing 12. sort 함수의 확장
arr.sort( function (x,y) { return x.date – y.date; } );
|
여기에서 arr는 유형 배열의 객체이며, 이것은 각각의 날짜 별로 arr의 모든 객체들을 분류할 것이다. 비교 함수와 이것의 정의는 sort 함수로 전달되어 sort 연산을 완료한다. 이 함수를 통해서,
- 각각의 xxJavaScript 객체는 날짜 프로퍼티를 갖는다.
- xxJavaScript의 배열 유형의 sort 함수는 선택적인 매개변수를 취하는데, 이것은 분류에 사용되는 비교 함수이다. 이는 C 라이브러리의
qsort 함수와 비슷하다.
- 동적인 HTML 생성을 위한 코드
- 이 예제에서, 고급 코드를 작성하여 배열에서 동적인 HTML을 만들어내는 방법을 볼 것이다. 배열에서 얻은 값에서 테이블들을 만들 수 있다. 또는, 배열의 내용을 사용하여 순위(Ordered) 리스트 및 무순위(Unordered) 리스트를 만들 수도 있다. 또한 수직 또는 수평 메뉴 아이템도 만들 수 있다.
Listing 13의 코딩 스타일은 배열에서 동적인 HTML을 생성하는데 사용된다. 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의 코드로 대체할 수 있다. Listing 14. 동적인 HTML을 생성하는 일반적인 방법
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는 이를 수행하는 한 가지 방법이다. Listing 15. 콜백에서 함수 호출하기
window.setTimeout(function(){alert(‘First!’);alert(‘Second!’);}, 5000);
|
Listing 16은 이를 수행하는 보다 고급 방식이다. 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의 코드를 사용할 수 있다. 아마도 이것은 여러분에게 잘 맞을 것이다. |
첫댓글 좋은정보 감사합니다.