클로저 – 01.람다 함수

문서 출처

람다식(Lambda Expressions)

람다식은 람다 대수(lambda calculus)에서 유래하였으며, 람다 대수에서 람다식(lambda expression)은 수학의 함수를 단순하게 표현하는 방법입니다. 다음은 x, y의 합을 계산하는 수학 함수 f를 보여줍니다.

이를 수학의 람다식으로 바꾸면, 다음과 같이 함수 이름 f를 빼고 간소하게 표현합니다.

람다식은 이름이 없는 함수로 표현됩니다. 또한 2개의 입력을 받는 위의 람다식을 한 개의 입력을 받는 함수로 단순화시키면 아래와 같은 형태로 다시 쓸 수 있습니다.

이와 같이 다중 인수를 갖는 함수를 단일 인수를 갖는 함수열로 변환하는 것을 커링(currying)이라고 합니다.

람다식의 계산을 하기 위해서는 괄호와 함께 x, y에 대입 될 값을 지정합니다. 람다식 (x, y) -> x + y에서 x, y 값을 지정하면 다음과 같은 람다식의 계산이 이루어집니다.

커링된 람다식 x -> (y -> x + y)에서 x, y 값을 지정하면 다음과 같은 람다식의 계산이 이루어집니다.

1930년대에 수학(mathematics)에 도입된 람다 대수와 람다식은, 1960년대 중반 프로그래밍 언어에 익명 함수(anonymous function) 형태로 도입되었고, 여러 프로그래밍 언어에서 지원되고 있는데 PHP는 5.3부터 지원합니다.

PHP의 화살표 함수(arrow function)로 람다식 ((x, y) -> x + y)(2, 3)을 작성하면 아래와 같습니다.

커링된 람다식 (x -> (y -> x + y))(2)(3)은 아래와 같습니다.

람다식은 크게 두 가지 특징을 가지게 됩니다.

  • 익명 함수 – 람다 대수는 이름을 가질 필요가 없다.
  • 커링 – 두 개 이상의 입력이 있는 함수는 한 개의 입력을 받는 함수로 단순화 될 수 있다.

이와 같이 람다식(lambda expression)은 이름이 없는 함수로 표현되므로 이를 익명 함수(anonymous function) 또는 람다 함수(lambda function)라고도 합니다.

익명 함수(anonymous function)

익명 함수는 함수의 이름이 없으므로 일반 함수처럼 호출할 수 없습니다. 따라서 변수에 할당한 후 할당된 변수를 통해 함수를 호출하거나 다른 함수에 인수로 전달합니다.

  • 변수에 저장되는 함수
  • 다른 함수의 인자로 넘기는 함수
  • 함수의 결과 값을 반환하는 함수

익명 함수를 변수에 할당 한 후 그 변수로 함수를 호출합니다.

익명 함수를 다른 함수에 인수로 전달합니다.

익명 함수를 함수의 결과 값으로 반환합니다.

이와 같이 익명 함수는 모두 아래와 같은 일급 함수(first-class function)의 특징*을 가지고 있습니다.

  • 변수에 할당될 수 있다.
  • 함수의 매개변수가 될 수 있다.
  • 함수의 반환 값이 될 수 있다.
  • 동적으로 함수가 생성될 수 있다.
  • 동일 비교의 대상이 될 수 있다.

* 학자에 따라 일급 함수 특징의 분류가 다를 수 있습니다.

PHP는 일급 함수(first-class function)를 지원합니다. 따라서 함수가 변수에 할당되거나, 변수에 의해서 참조되거나, 동적으로 생성될 수 있습니다.

함수는 다른 함수의 인자로 전달될 수 있고 함수가 다른 함수를 반환 값으로 반환하는 것도 가능합니다. 이런 기능을 고차함수(higher-order function)라고 합니다.

람다 함수(lambda function)

람다 함수는 람다식으로 표현되는 함수 구현을 말하며, 변수에 할당되거나 다른 함수에 인수로 전달될 수 있는 일급 함수(first-class function)의 특성을 가지고 있는 익명 함수(anonymous function)입니다. 동적으로 정의할 수 있고 변수에 바인딩되는 임시 함수로 함수 자체는 자신이 정의된 컨텍스트의 변수 스코프를 적용 받기 때문에 해당 변수가 스코프를 벗어나면 변수에 바인딩된 함수도 스코프를 벗어나게 됩니다.

프로그래밍 언어에서 람다 함수는 애초에 다른 함수에 인자로 넘기거나 함수의 결과 값으로 리턴할 용도로 만들어지기 때문에 이런 특징을 갖게 됩니다. 람다 함수를 사용하면 여러 컨텍스트에서 사용하는 임시 함수를 쉽게 정의할 수 있기 때문에 프로그래밍 작업이 쉬워지며, 최적의 성능을 발휘할 수 있도록 해 줍니다.

PHP 5.3부터 지원하는 람다 함수의 구문식은 function, 매개변수(parameters), 함수 몸체({ body })의 3부분으로 작성됩니다.

&는 선택 사항이며 함수가 참조를 반환해야 함을 나타냅니다. PHP 7.4부터 지원하는 화살표 함수(arrow function)을 이용하면 훨씬 간결한 구문으로 람다 함수를 정의할 수 있습니다. 화살표 함수의 구문식은 , 매개변수(parameters), 화살표 토큰(=>), 함수 몸체(expression)의 3부분으로 작성됩니다.

화살표 함수(arrow function)는 fn 키워드로 정의하며, return과 같은 키워드를 사용하지 않아도 되지만, 단일행으로 작성해야 합니다.

$lambda 변수에는 다음과 같은 방법을 통해 호출할 수 있는 callable 리소스가 포함됩니다.

람다 함수는 콜백 함수를 받는 PHP 함수에 많이 활용됩니다. 콜백으로 기명 함수(named function)를 넘길 수도 있지만 일회용으로 임시로 쓰일 함수라면 익명 함수를 사용합니다. 익명 함수를 사용하면 다른 곳에서는 사용되지 않는 일회용 함수를 빠르게 정의할 수 있습니다.

예를 들어 preg_replace_callback()을 호출해야 하는 코드를 작성할 때, 람다 함수를 사용하지 않는다면 아래와 같은 세 가지 방법이 있습니다.

람다 함수를 사용하지 않고 콜백 기능 수행

(1) 다른 위치에 콜백 함수 정의

preg_replace_callback() 함수의 위치가 아닌 다른 위치에 콜백 함수를 정의합니다. 이렇게 하면 콜백 함수를 정의한 위치와 이를 호출하는 부분이 떨어지게 되어 파일 전체에 속한 코드가 배포되고 가독성이 저하됩니다.

(2) 동일 위치에 콜백 함수 정의

preg_replace_callback() 함수와 동일한 위치에 콜백 함수를 정의합니다. 이 경우 함수가 한 번만 정의되도록 function_exists()를 사용해야 합니다. 여기에서 함수 정의 주위에 추가된 if()로 인해 소스 코드를 읽기 어렵게 만듭니다.

(3) 런타임 콜백 함수 생성

런타임에 함수를 생성하려면 현재 create_function()을 사용할 수 있습니다. 이 함수는 람다 함수와 동일한 결과를 얻을 수 있지만 이 접근 방식에는 몇 가지 단점이 있습니다. 우선, 문자열이 함수에 전달되기 때문에 리터럴 값(문자열, 정수, 부동 소수점)만 함수에 전달할 수 있으며, 객체는 복제 또는 리소스로만 전달할 수 있습니다. 그리고 문자열이 올바르게 이스케이프되었는지에 대해 주의해야 하며, 코드 편집을 위한  구문 강조(syntax highlighting)가 드러나지 않습니다. 특히 사용자 입력을 처리 할 때 모든 종류의 보안 문제가 발생할 수 있습니다.

람다 함수를 사용하여 콜백 기능 수행

콜백 함수를 받는 PHP 함수에 전달하는 함수가 다른 곳에서는 사용되지 않는 함수라면 람다 함수를 사용합니다. 람다 함수를 사용하면 단순하면서 효과적으로 매우 빠르게 정의할 수 있습니다. 람다 함수를 사용하지 않고 작성된 위 예제보다 훨씬 명확하면서 잘 정돈되어 가독성을 향상 시킬 수 있으며, 문자열 이스케이프에 신경 쓰지 않아도 되므로 코드 편집이 훨씬 수월해질 수 있습니다.

람다 함수를 인라인으로 넣을 수도 있습니다.

이와 같이 람다 함수를 사용하면 지정된 이름이 없는 함수를 만들어서 callable 타입의 매개 변수의 값이나 변수 값, 리턴 값 등으로 매우 유용하게 사용될 수 있습니다.

답글 남기기