들어가며
Rust, JavaScript/TypeScript에서 클로저(Closure)라고 부르는 익명 함수를 아시나요? Haskell, Python에서는 람다 표현식이라고 하는데요. 프로그래밍 언어 마다 람다 표현식을 어떻게 사용하는지 간단한 예제 코드로 알아보겠습니다.
Haskell
하스켈에서 람다 표현식은 \
로 시작합니다. 그리고 인자(parameters)를 나열하고 ->
뒤에 계산식을 구현합니다.
\x -> x
1부터 9까지 들어있는 리스트(list)에 있는 항목을 제곱하는 함수를 대응시키는 데모입니다. 결과는 리스트에 각 수의 제곱 값이 담긴 값이 나옵니다.
demo :: [Int]
demo = map (\x -> x * x) [1..9]
main :: IO()
main = print demo
-- [1,4,9,16,25,36,49,64,81]
Rust
러스트에서는 클로저라고 합니다.러스트의 클로저는 변수에 저장하거나 다른 함수에 인수로 전달하는 익명 함수(anonymous functions)입니다. 인자를 |
로 감싸는 표현이 Ruby 와 같네요.
|x| x
러스트는 같은 과정을 벡터에 넣어 처리합니다.
fn main() {
let vector: Vec<i32> = (1..10).collect();
let result = vector.iter().map(|x| x * x).collect::<Vec<i32>>();
println!("{:?}", result);
}
// [1, 4, 9, 16, 25, 36, 49, 64, 81]
Python
Haskell과 같이 람다 표현식이라 합니다.키워드 lambda
와 :
를 사용합니다.
lambda x: x
파이썬은 단지 한 줄로 리스트에 있는 값을 제곱하여 출력하는 코드를 작성할 수 있습니다. map 함수가 특정 객체의 멤버가 아닌 것이 하스켈 코드와 비슷하네요.
print(list(map(lambda x: x * x, range(1, 10))))
# [1, 4, 9, 16, 25, 36, 49, 64, 81]
JavaScript/TypeScript
JavaScript에서 Callback 함수도 익명함수죠? Rust와 같이 JavaScript도 이런 함수를 클로저라고 하는데요. JavaScript에서 클로저는 이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수를 말합니다. ES6 버전 이후 부터 Arrow Function를 이용하면 더욱 직관적으로 표현할 수 있습니다.
x => x
배열의 인덱스를 리스트의 값으로 받아 제곱하는 익명 함수에 대응시킵니다. 인덱스 값이 0부터 시작해서 1을 더해줬네요.
console.log([...Array(9).keys()].map(x => (x+1) * (x+1)));
// [
// 1, 4, 9, 16, 25,
// 36, 49, 64, 81
// ]
마무리
람다 표현식(Lambda expressions)는 학문적인 이론에서 비롯된 용어라면 클로저(Closure)는 기계적 구현 방법에서 비롯된 용어라 생각합니다.
용어도 중요하지만 같은 기능(feature)을 다양한 프로그래밍 언어에서 제공해준다는 것을 알고 적절한 순간에 사용할 줄 알아야 겠습니다.