Engineering2010. 5. 28. 08:48

지난 글에서 이야기 했던 람다(Lambda)의 배경 개념에 대해 알아보겠습니다.

람다 함수는 First-Class Object?
프로그래밍 언어를 이루는 class, struct, int와 같은 개체들 중에서 아래 조건을 만족하면 First-Class Object로 분류합니다. (First-Class Object는 분류의 한 갈래를 의미하는 것이지 상하 관계를 의미하진 않습니다.)


- 변수와 자료구조에 저장하고 사용할 수 있다.

- 함수의 입력 값으로 사용할 수 있다.
- 함수의 반환 값으로 사용할 수 있다.
- 실행 시간에 생성할 수 있다.

즉, 기존 C++에서는 class, struct, int 등이 First-Class Object 였고  아래 예제에서 볼 수 있듯이 C++0x에서 람다 함수(Lambda Function)가 First-Class Object의 조건들을 만족시킵니다.

...
int main()

{

string text = "C++0x Lambda!";

 

// 1. "코드 조각" 변수에 대입하기

function<void()> lambda = [=]()

{                               

cout << text << endl;

};

 

// 2. "코드 조각"을 자료구조에 저장하기

vector< function<void()> > container;

{               

container.push_back( lambda );

container.push_back( [=](){ cout << text << endl; } );

};

 

// 3. "코드 조각"을 함수의 입력 파라미터로 사용하기

for_each( container.begin(), container.end(), [](const function<void()>& f){ f(); } );

 

return 0;

}


위 조건들을 통해 First-Class Object들은 프로그래밍 언어에서 별 다른 제약 조건 없이 변수로 사용할 수 있게 됩니다. 최근 여러 언어들이 함수를 First-Class Object로 제공하는 이유도 함수를 값 처럼 사용할 수 있게 되면 여러 모로 유용하기 때문입니다. 특히 함수는 다른 First-Class Object들을 생성하거나 조작하는 일련의 코드 묶음이기 때문입니다.

C++0x에서는 람다 함수(Lambda Function)를 First-Class Object로 제공함으로써 코드 조각을 일반 변수처럼 사용할 수 있게 해줍니다.



람다 함수는 Higher-Order Function?

함수의 입력 값으로 함수를 전달 받거나 함수의 결과 값으로 함수를 반환할 수 있을 때 Higher-Order Function이라고 합니다. 아래 예제 코드를 보면 쉽게 알 수 있습니다.

 

int main()

{

// 1. 람다 함수를 반환 값으로 한다.

auto g = [](int x) -> function<int (int)>

{          

return [=](int y) { return x + y; };

};

 

// 2. 람다 함수를 입력 값으로 받는다.

auto h = [](const function<int (int)>& f, int z)

{

return f(z) + 1;

};

 

auto a = h( g(7), 8 );

 

cout << a << endl;

}



예제를 보면 h( g(7), 8 )과 같이 표현된 것을 볼 수 있습니다. 마치 수학 책에서 보던 h( g(x), y )처럼 표현할 수 있는 것입니다. 람다 함수는 C++0x에서 First-Class Object 조건을 만족시키기 때문에 Higher-Order Function의 요구사항 또한 만족시킵니다.


람다 함수는 Closure?
클로저(Closure)는 함수를 호출한 상위 코드 블록의 변수들이 호출된 함수와 묶인 것을 뜻합니다. 즉 호출된 함수는 상위 코드 블록의 외부 변수와 묶여 자기만의 상태를 갖게 되는 것입니다.
C++0x에서는 람다 함수(Lambda Function)가 상위 코드 블록의 변수들과 묶여 클로저(Closure)가 될 수 있다. 이때 람다 함수에서 외부 변수들을 참조하는 것을 ‘캡처’라고 말합니다.
캡처(Capture)는 두 가지 방법으로 할 수 있습니다. 람다 시작을 나타내는 [] 기호 사이에 =과 & 기호를 이용할 수 있습니다. [=]은 값 복사를 의미하고 [&]는 값 참조를 의미합니다. 아래 예제 코드를 보시죠.

 

void capture()

{

int a = 0;

int b = 1;

int c = 2;

 

// 1. default 값 복사 캡처. 상위 코드 블록의 지역 변수 모두 값 복사 가능

[=](){ cout << a << “ “ << b << endl; }();  // 0 1 출력

 

// 2. default 값 참조 캡처. 상위 코드 블록의 지역 변수 모두 값 참조 가능

[&](){ cout << a << “ “ << b++ << endl;}(); // 0 1 출력

 

// 3. default 값 복사 캡처, b와 c 참조 캡처

[=, &b, &c](){ cout << a << “ “ << b << “ ” << c << endl; }();  // 0 2 2 출력

}



이번 포스팅에선 몇 가지 배경 개념들을 알아봤는데요, 도움이 되셨는지 모르겠습니다 ;)
다음 글에선 람다 함수의 활용 방안에 대해 알아보겠습니다.

Posted by TedAhn