본문 바로가기
느리게 변하는 지식

lambda in computer programming

by oncerun 2023. 7. 14.
반응형

우선 우리는 표현식과 구문을 구분할 줄 알아야 한다. 

 

구문(statement)은 이름에서 나타난다. 반복문, 조건문, 분기문, 선언문 등등 프로그램의 흐름 제어나 구조를 생성할 때 사용되는 문법이다.

 

표현식(expression) if, while, for문에서 사용되는 조건식이 있다. 이는 표현식이다. 이는 값으로 실행 시점에 값으로 표현되어 참 혹은 거짓의 값을 나타낸다. 

 

이를 이해하면 프로그래밍 언어가 발전됨에 따라 늘어나는 간소화된 문법을 이해하는데 큰 도움이 된다. 

 

이제 Wikipedia에서 lamba, Anonymous function을 검색해 보자.

 

In computer programming, an anonymous function (function literal, lambda abstraction, lambda function, lambda expression or block) is a function definition that is not bound to an identifier.

 

bold 체의 단어의 뜻을 확인해 보자.

 

1. function literal : 함수를 값으로 취급하여 변수에 할당하거나 다른 함수의 인자로 전달할 수 있도록 하는 함수를 표현하는 방법 중 하나입니다. 함수 리터럴은 함수의 이름이나 식별자를 사용하지 않고도 함수를 정의할 수 있도록 합니다.

 

함수 선언문이 아니라 함수 표현식으로 사용한다는 의미로 생각된다. 즉 함수는 평가 대상이며 이를 값으로 취급하여 할당, 매개변수, 조건식 등 표현식이 사용되는 곳에도 사용할 수 있음을 뜻합니다.

 

2. lambda abstraction : 람다 추상화는 함수를 정의하는 방법으로, 람다 함수의 입력 변수와 함수 본체를 정의합니다. 

λ<입력 변수>.<함수 본체>

이는 람다의 추상화입니다. 람다 기호, 함수의 매개변수, 본체는 매개변수를 이용하여 계산을 수행하는 코드 또는 표현식을 말합니다. 

 

3. lambda function은 프로그래밍에서 익명 함수를 나타내는 용어입니다.  익명 함수는 말 그대로 이름이 없는 함수로서, 일회성으로 사용되거나 다른 함수의 인자로 전달되는 등의 상황에서 유용하게 사용됩니다.

 

4. lambda expression: 람다 표현식은 함수 리터럴이나 람다 함수를 간결하게 표현하기 위해 사용됩니다. 

 

각 단어의 의미가 조금씩 다른 것 같지만 하나의 용어로 읽어도 큰 문제가 없어 보입니다.

그 이유는 전부 익명 함수를 표현하려는 방법으로 귀결되는 것 같습니다. 

 

계속 읽어보면 함수의 정의가 식별자에 바운딩되지 않는 것을 의미한다고 합니다. 

 

Names

 

람다 추상화, 람다 함수, 람다 표현식이라는 이름은 람다 미적분학에서 함수의 추상화 표기법을 의미합니다. 

 

usual function f(x) = M would be written (λx.M) (M is an expression that uses x). Compare to the Python syntax of lambda x: M.

 

The name "arrow function" refers to the mathematical "maps to" symbol, x  M. Compare to the JavaScript syntax of x => M

 

람다 미적분학에서 사용되는 함수의 추상화 표기법을 각 프로그래밍 언어가 이를 구현한 것으로 보입니다.

 

 

Use

 

익명 함수의 사용은 스타일의 문제입니다. 익명 함수를 사용하는 것이 문제를 해결하는 유일한 방법은 아니며, 각 익명 함수를 명명된 함수로 정의하고 이름으로 호출할 수도 있습니다. 일부 프로그래머는 익명 함수를 사용하여 한 줄짜리 일반 함수로 코드를 어지럽히지 않고 재사용할 수 없는 특정 코드를 캡슐화하기도 합니다.

일부 프로그래밍 언어에서 익명 함수는 일반적으로 이벤트를 콜백에 바인딩하거나 특정 값에 대한 함수를 인스턴스화하는 등 매우 특정한 목적으로 구현되며, 이는 보다 일반적인 명명된 함수를 호출하는 것보다 더 효율적이고 가독성이 높으며 오류가 덜 발생할 수 있습니다.

 

이를 통해 알 수 있는 건 람다는 함수의 추상화 표기법이라는 것입니다. parameter와 이를 사용하는 함수 본체를 표현하는 것이며 익명 함수가 Alonzo Church가 모든 함수가 익명인 람다 미적분을 발명함으로써 발전되었다고 하니 어느 정도 이해가 됩니다. 

 

이러한 개념을 프로그래밍 함수에 적용시킨 것이 지금까지 발전되어 온 것으로 생각됩니다

 

Closures

 

클로저가 익명 함수의 개념에서 나오는 것이 흥미롭습니다.

 

위키피디아의 클로저의 소개는 다음과 같습니다.

 

클로저는 바운딩된 변수들이 포함된 환경 안에서 평가된 함수들입니다.

 

말이 어렵군요. 

 

이를 이해하기 위해 일급 객체 함수가 무엇인지 확인해야 합니다.

 

우선 일급 객체는 프로그래밍 언어에서 특정한 조건을 충족하는 개체를 가리키는 용어입니다.

 

1. 변수에 할당할 수 있다.

2. 인자로 전달할 수 있다.

3. 반환값으로 사용할 수 있다.

 

일급 객체 함수는 위에서 설명한 일급 객체의 조건을 충족하는 함수를 가리키는 용어입니다. 

 

함수를 일급 객체로 다루는 프로그래밍 언어에서는 함수를 변수로 할당하거나 인자로 전달할 수 있고, 함수를 반환값으로 사용할 수 있습니다. 

 

위키의 정의를 최대한 풀어보려고 합니다.

 

클로저, 렉시컬 클로저, 함수 클로저는 식별자에 바인딩된 개체가 유효한 범위를  프로그램 내 가질 수 있도록 구현하는 일급 함수를 지원하는 언어의 프로그래밍 기법입니다.

 

일반적으로 클로저는 환경을 저장하는 함수의 저장소라고도 불립니다. 환경은  함수의 각 자유 변수를 클로저가 생성될 때 식별자가 바인딩된 값 또는 참조를 연결하는 매핑입니다. 

 

자유변수는 변수가 정의되지 않은 상태로 사용되는 변수를 말합니다.

 

예를 들어 'Lisa found her book"에서 her은 Lisa가 될 수도 있고 다른 여성을 의미할 수도 있습니다.

즉 정의되지 않은 상태로 사용되고 있죠. 

 

자유변수는 해당 변수의 정의가 있는 다른 범위나 스코프에서 찾아볼 수 있습니다.  프로그래밍적으로 예시를 들면 함수 내에서 함수 외부에서 선언된 변수를 사용하는 경우 해당 변수는 함수 내에서는 자유변수가 됩니다. 

 

일반 함수와 달리 클로저를 사용하면 함수가 범위 밖에서 호출되는 경우에도 클로저의 값 또는 참조 복사본을 통해 캡처된 변수에 액세스 할 수 있습니다.

 

 

자유 변수에 대한 개념을 기억하면 클로저 예시를 이해하는데 큰 어려움이 없습니다.

 

def f(x):
    def g(y):
        return x + y
    return g  # Return a closure.

def h(x):
    return lambda y: x + y  # Return a closure.

# Assigning specific closures to variables.
a = f(1)
b = h(1)

# Using the closures stored in variables.
assert a(5) == 6
assert b(5) == 6

# Using closures without binding them to variables first.
assert f(1)(5) == 6  # f(1) is the closure.
assert h(1)(5) == 6  # h(1) is the closure.

 

하나씩 이해하려고 하시면 됩니다.

def f(x):
    def g(y):
        return x + y
    return g  # Return a closure.

def h(x):
    return lambda y: x + y  # Return a closure.

# Assigning specific closures to variables.
a = f(1)
b = h(1)

 

함수는 자유 변수를 클로저가 생성될 때 환경에 저장한다고 했습니다.

 

함수가 인스턴스화될 때 -> 함수가 호출될 때 생성된다고 합시다.

 

a = f(1)

 

호출되었습니다. 이때 f(x)의 inner function인 g(y) 함수가 평가되고 반환됩니다. 

 

이때 g(y)의 상황을 생각해 보면 x는 자유변수입니다. 자신 범위에 없는 변수이기 때문이죠. 

 

그 값이 1이며, 클로저의 정의에 따라 이 값을 저장해야 합니다. "x = 1"

 

그리고 함수는 return을 만나 반환됩니다. 실제 콜 스택에서 이 함수의 호출 콘텍스트는 종료되었을 것입니다. 

 

일반적이라면 모든 자원을 반환하고 사라져야 합니다.

 

그런데 함수를 식별자에 할당했습니다. 

 

a = f(1) , a는 g(y)이고 x = 1인 환경을 저장하고 있는 클로저가 됩니다. 

 

assert a(5) == 6

 

g(y)는 x + y라는 표현식의 값을 반환하도록 되어 있습니다. 

 

x라는 변수를 찾는데, 이는 환경 내에 저장되어 있기에 x는 1입니다. y의 값으로 5가 들어왔으니 그 값은 6일 것입니다. 

 

assert f(1)(5) == 6  # f(1) is the closure.

 

이는 currying이라는 개념인데, 여러 매개 변수를 단일 매개변수로 표현하는 것을 말합니다. 

 

f(1)은 클로저라고 했습니다. g(y)가 반환되고, 생성 당시의 환경에는 x = 1이라는  변수가 저장되어 있습니다.

그대로 g(5)를 호출했기 때문에 저장된 x 변수를 사용해 6이라는 결과가 도출됩니다.

 

설명과 예시를 생각해 보면 클로저라는 것은 매우 다양하게 활용될 수 있습니다.

 

자유 변수에 익명 함수를 담았다고 생각해 봅시다.

 

그리고 클로저를 통해 자유 변수를 환경에 저장합니다. 

 

그러면 해당 함수, 객체를 사용할 때 익명 함수가 저장되어 사용될 수 있습니다. 이러한 개념이 뭐가 있을까요?

 

콜백함수가 생각합니다. 자바스크립트의 API는 매우 많은 콜백함수가 존재합니다. 

 

이벤트 리스너만 생각해 봐도 이벤트 시 발생할 함수를 정의하는데, 이때 우리는 익명 함수, 람다 함수, arrow function을 사용합니다. 하지만 모든 함수가 클로저인 것은 아닙니다. 

 

이벤트리스너의 콜백 함수에서 외부에 정의된 변수를 자유 변수로 갖는 경우 클로저로 간주되고, 이 콜백함수는 자유 변수에 대한 참조를 환경에서 유지하고 있기 때문입니다. 

 

그래서 이 참조를 통해 변수에 접근하고 수정할 수 있는 것입니다.

 

그럼 왜 익명 함수 정의에 클로저가 있을까요?

 

이는 프로그래밍적으로 생각해 볼 수 있습니다. 콜백 함수를 생각했을 때 이벤트에 필요한 모든 콜백 함수를 식별자에 할당하고 전달할 수 있습니다.

 

그런데 이러한 모든 콜백 함수를 만드는 것은 너무 비실용적입니다. 

// 비 실용적인 예시: 모든 콜백 함수를 만드는 코드

// 이벤트 핸들러 함수
function eventHandler(callback, x, y) {
  callback(x, y);
}

// 모든 콜백 함수 정의
function callbackA(x, y) {
  console.log("Callback A:", x + y);
}

function callbackB(x, y) {
  console.log("Callback B:", x - y);
}

function callbackC(x, y) {
  console.log("Callback C:", x * y);
}

function callbackD(x, y) {
  console.log("Callback D:", x / y);
}

const x = 5;
const y = 3;

eventHandler(callbackA, x, y);
eventHandler(callbackB, x, y);
eventHandler(callbackC, x, y);
eventHandler(callbackD, x, y);

 

이를 다음과 같이 익명 함수와 클로저를 사용하여 간단하게 만들 수 있습니다.

// 클로저를 통한 익명 함수로 간단하게 만들기
const x = 5;
const y = 3;
// 이벤트 핸들러 함수
function eventHandler(callback) {
  callback(x, y);
}

// 익명 함수를 콜백으로 사용
eventHandler( (x, y) => {
  console.log("Result:", x + y);
});

 

이러한 프로그래밍 기법을 소개하기 이해 익명 함수 wikepedia에 클로저를 소개하는 것 아닌 가 싶습니다.

 

 

주제는 람다, 익명 함수이므로 마지막으로 정리하겠습니다.

 

람다에 대한 다양한 정의가 있습니다. 람다 함수, 익명 함수... 결국 이는 함수의 추상화 표기법이었습니다.

 

함수의 추상화된 표기법을 프로그래밍 기술로 사용하면서 각 프로그래밍 언어에 맞게 형식이 정해졌고

 

이를 일급 객체 함수로 취급함으로써 상황에 따라 이점을 얻을 수 있다.

 

라고 정리할 수 있을 것 같습니다.

 

 

 

 

 

 

 

https://en.wikipedia.org/wiki/Closure_(computer_programming) 

https://en.wikipedia.org/wiki/Anonymous_function

반응형

'느리게 변하는 지식' 카테고리의 다른 글

CDN  (0) 2022.12.17
타임존  (0) 2022.12.06
아파치 웹 서버를 리눅스에서 설치할 때 왜 여러 패키지를 받을까?  (0) 2022.11.12
데드락  (0) 2022.08.04
CPU 작동 원리  (0) 2022.04.08

댓글