TL;DR

  • 아래 내용은 javascript 중심의 개인적 견해입니다.
  • 람다는 익명함수를 정의 하는 편리한 방법입니다. 하지만 자바스크립트에서는 별도의 방법 없이도 익명함수를 선언할 수 있기 때문에 람다라는 표현을 쓰이는 경우가 어색한거 같습니다.

-

  • 람다식은 수학자 알론조(Alonzo Church)가 발표한 람다 계산법에서 사용된 식으로, 이를 제자 존 매카시(John Macarthy)가 프로그래밍 언어에 도입했습니다.
  • 필자는 람다를 자바에서 처음 알게 되었지만 자바는 나중에 수용한 것입니다. 자바는 나중(자바 8)에야 이 표현을 받아들이게 되었습니다.
  • 현재 사용되고 있는 람다의 근간은 수학과 기초 컴퓨터과학 분야에서의 람다 대수입니다.
  • 람다함수를 알아보기 전에 람다 대수에 대해 먼저 알아보겠습니다.

람다대수 란?

  • 람다 대수는 수학에서 사용하는 함수를 보다 단순하게 표현하는 방법입니다.

1. 람다 대수는 이름을 가질 필요가 없습니다.

  • 이름 없는 메서드를 익명 함수(anonymous function)라고 부릅니다.
  • 익명 함수는 언어별로 표현 방식이 다르지만 일급객체(First-Class citizen)라는 공통적인 특징이 있습니다.
  • 함수가 일급 객체가 되면 일급 함수라고 부를 수 있습니다.

일급 객체

  • 일급 객체는 아래의 4가지 요소를 모두 충족해야 합니다.
    • 모든 요소는 함수의 실제 매개변수가 될 수 있습니다.
    • 모든 요소는 함수의 반환 값이 될 수 있습니다.
    • 모든 요소는 할당 명령문의 대상이 될 수 있습니다.
    • 모든 요소는 동일 비교의 대상이 될 수 있습니다.
  • 자바스크립트에서 함수는 1급 객체입니다. 자바에서는 함수가 1급 객체가 아니기 때문에 람다를 통해 이를 보완합니다.

2. 두개 이상의 입력이 있는 함수는 최종적으로 1개의 입력만 받는 람다 대수로 단순화 될 수 있습니다.

  • 위 특징은 커링의 특징과 같습니다.

람다 란?

  • 그렇다면 람다란 무엇일까요?
  • 우선 람다의 장단점을 알아보겠습니다.

장점

  • 코드가 간결해 집니다.
    • 람다 함수를 통해 불필요한 루프문의 삭제가 가능하며, 동일한 함수를 재활용할 수 있는 여지가 커집니다.
  • 필요한 정보만을 사용하는 방식을 통한 퍼포먼스 향상 시킵니다.
    • 지연 연산을 지원하는 방식을 통하여 효율적인 퍼포먼스를 기대할 수 있습니다. 이 경우 메모리상의 효율성 및 불필요한 연산의 배제가 가능하다는 장점이 있습니다.

단점

  • 어떤 방법으로 작성해도 모든 원소를 전부 순회하는 경우는 람다식이 조금 느릴 수 밖에 없습니다.
    • 어떤 방법으로 만들어도 최종 출력되는 bytecode나 어셈블리 코드는 단순 반복문보다 몇 단계를 더 거치게 됩니다.
  • 익명함수의 특성상 함수 외부의 캡처를 위해 캡처를 하는 시간제약, 논리제약적인 요소도 고려해야 하며, 디버깅 시 함수 콜스택 추적이 극도로 어렵습니다.
  • 람다식을 남용하면 오히려 코드를 이해하기 어려울 수 있습니다.

자바스크립트에서 람다란 ?

  • 이제 람다의 견해에 대해 살펴보겠습니다.
  • 아래의 내용은 자바스크립트 관점에서만 생각해 보도록 하겠습니다.

람다 ==== 익명 함수 ?

  • 익명 함수는 람다인가?
  • 이를 위해 익명 함수에 대해 알아 보겠습니다.

익명함수

  • 익명함수는 선언적함수와 달리 변수에 저장되는 함수 데이터가 함수명을 가지고 있지 않습니다.
  • 익명함수의 경우에는 익명 함수 생성 이후에 호출을 해야 합니다.

람다는 익명함수라는 의견

  • 람다는 단순히 익명의 함수입니다(이름이 없는 함수입니다)
  • 람다식이란 ‘식별자 없이 실행가능한 함수’라고도 합니다.
  • ‘lambda’ 또는 ‘lambda expressions’라는 단어는 대부분 익명 함수를 나타냅니다.
  • 람다 미적분은 함수를 유일한 ‘데이터 구조’로 사용하는 최소한의 프로그래밍 언어 / 수학적 계산 모델입니다. lamdba 미적분학에서 람다 기호는 (익명) 함수를 만드는 데 사용됩니다.
  • 오브젝트 책 부록에서 ‘최근의 객체지향 언어들은 이름 없는 메서드를 정의할 수 있게 허용합니다. 이들은 다양한 언어에서 익명 함수(anonymous function), 함수 리터럴(function literal), 람다 표현식(lambda expression) 등의 다양한 이름으로 불린다’고 합니다.
  • 람다식, 또는 람다 함수는 프로그래밍 언어에서 사용되는 개념으로 익명 함수(Anonymous functions)를 지칭하는 용어입니다. 프로그래밍 언어학적으로 파고들면 이것만 한 달 이상 배우는 경우도 많으며, 실제로 여러 대학들에서 사용하는 프로그래밍 언어 교재에서도 꽤나 많은 분량을 차지하는 개념입니다. 실무적으로는 코드의 간결함, 지연 연산을 통한 퍼포먼스 향상, 그리고 기존 이터레이션 관련 코드를 구현하는 데 있어 불필요한 부분들을 제거할 수 있다는 점에서 비교적 중요하게 다루어지고 있습니다. 람다식은 주로 고차 함수에 인자(argument)로 전달되거나 고차 함수가 돌려주는 결과값으로 쓰입니다.
  • 프로그래밍에서 ‘Lambda’는 일반적으로 ‘lambda function’(또는 ‘lambda expression’, ‘lambda term’)을 의미합니다. function이 사용 전에 정의 된 명명 된 코드 블록 인 경우 ‘lambda function’은 프로그래밍 언어에서 일급 시민으로 사용될 수 있는 사용 대신 정의 된 코드 블록 (또는 표현식)입니다.
  • 익명 함수는 람다 대수로부터 영향을 받아 만들어진 프로그래밍에서 함수를 표현하는 방식의 일종입니다. 비교적 최근부터 대부분의 프로그래밍 언어가 익명 함수를 지원합니다. 흔히 Java가 8버전 부터 람다를 지원하게 되었다고 하는데 이때 람다가 익명 함수(Lambda abstraction)를 말합니다.

익명함수는 람다인가에 대한 필자의 의견

  • 람다식은 익명함수와 통하는 말이라고 할 수는 있습니다. 하지만 람다식과 익명 함수가 같다고 보기는 어렵습니다. 람다식은 그 컨텍스트에 바로 실행되는 경우를 포함하고 있습니다. 익명함수는 람다처럼 돌기도 하고 변수에 넣어놓고 있다가 돌릴수도 있습니다.

람다 === 일회용 함수 ?

  • 이번에는 컨텍스트에 바로 실행되는 경우에 집중해 보겠습니다.
  • 함수를 따로 만들지 않고 코드 한 줄에 함수를 써서 그것을 호출하는 방식을 일회용 함수라고 합니다.
  • 바로 실행되는 경우라면 일회용 함수라면 람다인가에 대해 알아보겠습니다.

일회용 함수가 람다라는 의견

  • 함수 중에는 필요에 따라 일회용으로 사용되는 함수가 존재합니다. 그것을 ‘람다(lamda)함수’ 라고 합니다.

일회용 함수가 람다인가에 대한 필자의 의견

(function() {})();
  • 위 방식(즉시실행함수)은 컨텍스랑 변수 스콥 제약하려고 익명함수 만들어서 실행하는 경우입니다. 이를 람다라고 표현하기에는 정의에 맞지 않고 용도가 다르기 때문에 일회용 함수와 람다가 같지 않습니다.

람다 === arrow funtion ?

  • 자바스크립트에서 람다를 검색해보면 arrow function이 람다라는 의견이 가장 많이 나옵니다.

arrow function이 람다라는 의견

  • 자바의 람다와 자바스크립트의 arrow funtion은 그 생김새와 용도가 비슷하기 때문입니다.
  • 함수적 프로그래밍을 위해 자바 8부터 람다식(Lambda Expressions)을 지원하면서 기존의 코드 패턴이 많이 달라졌습니다. 자바스크립트에서 주로 봤었던 문법들을 이제 자바에서도 종종 보이곤 합니다.
  • ES2015에서는 Arrow function이 도입되면서 익명함수를 보다 람다스럽게 표현할 수 있게 되었습니다.
// ES5.1
[0, 1, 2, 3, 4].map(function(n) {
	return n * n;
});

// ES2015
[0, 1, 2, 3, 4].map(n => n * n);

arrow function이 람다인가에 대한 필자의 의견

  • javscript의 모든 함수는 일급 객체이므로 javascript에서 arrow function이 람다라고 보기는 어렵습니다.
  • javascript에서는 function을 function과 arrow function으로 나눕니다. 둘다 anonymous function으로 사용 가능합니다.
    • Arrow function은 anonymous function 을 표현하는 방법 중 하나일 뿐입니다.
    • 함수 포현식으로도 가능
    const a = () => {};
    const b = function() {};
  • arrow function과 람다는 자바의 형태와 비슷할 뿐 큰 연관 관계를 찾지 못했습니다.

람다 === 클로저 ?

  • 2번째 정의인 두개 이상의 입력이 있는 함수는 최종적으로 1개의 입력만 받는 람다 대수로 단순화 될 수 있습니다.에 집중해 보겠습니다.
  • 클로저를 통해 이를 구현할 수 있습니다. 클로저는 익명 함수를 리턴하기 때문에 이 정의에 더욱 잘 맞는거 같아 보입니다.

클로저가 람다라는 의견

  • 람다는 닫는 것과 같이 선언 된 컨텍스트에서 걸리는 상태를 포함 할 수 있습니다.
  • 언어에서 중첩 함수를 선언 할 수 있으면 명명 된 함수도 람다가 가능합니다.
  • 람다의 가장 흔한 용례로는 콜백을 꼽을 수 있습니다. 콜백으로 Named function을 넘길 수도 있지만, 대개의 경우 일회용 함수를 넘기기 위해서 익명 함수를 사용하게 됩니다. 클로저도 마찬가지로 익명함수를 사용합니다.
function adder(a) {
	return function(b) {
		return a + b;
	};
}

var add5 = adder(5);
add5(10); // 15
  • add5라는 함수의 입장에서 생각해볼 때, 자신의 스코프 내에 있는 b라는 변수는 인자로 받은 변수이고 해당 스코프 내에 갇혀있지만, a라는 변수는 대체 어디서 와서 사용되고 있는지 알 수가 없습니다. 이때의 a를 자유 변수(Free variable), b를 묶인 변수(Bound variable) 라고 부릅니다. 위의 람다식에서는 자유 변수와 묶인 변수를 하나씩 사용하고 있습니다. 람다식은 사용하는 변수의 종류에 따라 두 종류로 나눌 수 있습니다. 바로 닫힌 람다식(Closed expression) 과 열린 람다식(Open expression)입니다. 람다 표현식에서 사용하는 변수들이 모두 묶인 변수일 때 닫힌 람다식이라고 부릅니다. 그리고 람다 표현식에서 사용하는 변수들 중 하나라도 자유 변수가 있을 때 열린 람다식이라고 부릅니다. 클로저는 바로 열린 람다식을 닫힌 람다식으로 만드는 것입니다. 클로저는 람다식 내의 모든 자유 변수를 스코프 내로 가져와 묶습니다. 그렇기 때문에 클로저는 만들어진 환경을 기억하는 것처럼 보입니다.
var a = 1;
function freeAdder(b) {
	return function(c) {
		return a + b + c;
	};
}

var add2 = freeAdder(2);
add2(3); // 6

a = undefined;
add2(3); // NaN
  • 앞서 설명했던 케이스에 글로벌 변수인 a가 추가되었습니다. 그런데 클로저의 입장에서 보면 b도 자유 변수이고, a도 자유 변수이므로 똑같이 묶어야 할 것으로 보입니다. 하지만 위에서 본 대로 실제 동작은 그렇지 않습니다. javascript에서는 클로저를 만들면 클로저가 만들었을 때의 환경이 만들어지는데, 위의 경우에서는 생성당시의 환경에 b라는 변수는 존재했지만 a라는 변수는 단지 참조만 하고 있었으므로 클로저에도 동일한 환경이 구성된다는 것입니다. 따라서 스코프체인에 상위 스코프가 포함되어 있으므로 상위 스코프에서 a를 탐색하여 참조하게 됩니다.

모든 람다 기능이 익명의 기능은 아니며 그 반대도 마찬가지 ?

  • 익명 함수는 이름에서 알 수 있듯이 이름이 없는 함수입니다. 함수 표현식을 정의하는 데 가장 널리 사용되는 방법입니다. 이 함수 표현식은 런타임에 생성되며, 프로그램 실행이 시작 되자마자 실제 선언 전에 호출 될 수 있는 함수 선언과 달리 호출되기 전에 선언 / 정의되어야합니다. 익명 함수를 사용하여 IIFE (Inmediately Invoked Function Expressions)에서 캡슐화를 촉진 할 수도 있습니다. 반면에 람다 식은 함수가 데이터처럼 전달 될 수 있는 추상화입니다. javascript에서는 모든 것을 객체로 취급하여 함수가 1급 객체입니다. 즉, 함수를 다른 함수에 매개 변수로 보내고 호출 된 함수에서 반환 값으로 검색 할 수도 있습니다.
  • Lambda 표현식은 대부분의 명령형 프로그래밍 언어가 선언을 위해 팻 화살표 표기법 (=>)을 지원한다는 사실에 의해 촉진되었습니다(Java 프로그래밍 언어는 얇은 화살표 (->) 기호를 사용하지만). C#에서 람다 식은 일반적으로 인라인으로 작성되며 호출되는 함수에는 대리자가 필요합니다. 그들은 LINQ에 의해 대중화되었습니다.
  • javascript에서 람다 함수와 익명 함수를 구별하는 가장 중요한 점은 람다 함수의 이름을 지정할 수 있다는 것입니다. 이 이름은 디버깅 중에 도움이 될 수 있습니다. 이는 람다 함수가 반드시 익명 일 필요는 없으며 익명 함수가 데이터와 같이 전달되지 않는 경우 반드시 람다 식일 필요는 없음을 보여줍니다. arrow function은 this의 사용에 집중하는 것이 더 중요합니다.

람다식이란 일종의 함수형 프로그래밍에 적합한 문법적 표현방식 ?

  • 람다식은 익명함수(anonymouns function)을 생성하기 위한 식으로 객체 지향 언어보다 함수 지향 언어에 가깝습니다. 람다 형태는 매개변수를 가진 코드 블록이지만, 런타임 시에는 익명 구현 객체(추상메소드를 한개 포함한)를 생성합니다.
  • 람다식은 결국 로컬 익명 구현객체를 생성하게 되지만, 이 람다식의 사용 목적은 인터페이스가 가지고 있는 메소드를 간편하게 즉흥적으로 사용하는 것이 목적입니다.
  • 람다 형식은 인공지능 분야나 AutoCAD라는 설계 프로그램에서 쓰이는 Lisp 언어에서 물려받았다고 하는데요, 함수를 딱 한 줄만으로 만들게 해주는 훌륭한 녀석입니다. Lisp는 대표적인 함수형 언어입니다.
  • class 선언이 필요없고 인라인화가 가능합니다.

중간 결론

  • 컨텍스트 안에서 한번 쓰이고 재사용 되지 않는 함수라고 생각합니다.
  • 익명함수를 이용해 클로저를 사용할 때 그 함수를 지칭 할 수 있다고 생각합니다.

최종 결론

  • 람다는 익명함수를 정의 하는 편리한 방법입니다. 하지만 자바스크립트에서는 별도의 방법 없이도 익명함수를 선언할 수 있기 때문에 람다라는 표현을 쓰이는 경우가 어색한거 같습니다.

참고