Functional Programming과 Lambda Calculus의 관계

람다대수(Lambda Calculus)가 왜 자꾸 함수형 프로그래밍(Functional Programming)에서 언급이 될까?

FP를 공부하면 끊임없이 쫓아오는 것이 람다대수 이야기다. 처음 공부할 때는 람다가 익명함수고 람다 대수는 그 연산이니까 함수형 프로그래밍이랑 비슷한 개념정도로 막연하게 이해하고 있었다. 하지만 공부를 하면서 조금씩 그 의미와 그로 인해 이해되는 것들이 있어 몇가지 정리해본다. 물론 아직도 공부 중이기에 더 얻는 깨달음이 있으면 업데이트는 말고 추가로 글을 쓰자.

우선 Labmda는 수학에서 함수를 의미한다. 우리가 중학교때부터 배워왔던 y=ax+b 와 같은 함수. 이것을 람다로 쓰면 𝜆x.ax+b 로 된다. 그래서 수학에서 사용하던 함수는 람다였고, 보는 것처럼 수학적 표현에서 함수명을 표기할 방법이 없다는 것을 보면, 프로그래밍상 익명 함수가 수학에서 사용한 함수 즉 람다가 된다. 함수형 프로그래밍은 수학식의 프로그래밍을 표방하고 있고, 이 수학적 표현을 모두 안고 만들어진 언어가 Haskell이다. Haskell 소개의 처음에 나오는 것이 Haskell == Lambda Calculus, 즉 함수의 연산을 표현하는 언어란거다.

그래서 함수형 프로그래밍에 최적화된 언어인 Haskell이 람다대수를 표현한 언어이기에 함수형 프로그래밍이란 람다대수를 표현하기 위한 것으로 이해해도 무방해보인다.

함수형 프로그래밍을 위한 함수형 언어의 특징은 뭘까?

함수형 프로그래밍은 위에 내가 이해한 바에 따르면 함수들의 연산을 프로그래밍으로 만들어내는 것이다. 이미 익숙한 언어들도 따지고 보면 함수로 만들어지는 것인데 뭐가 다르냐라는 반문을 나도 했었다. 하지만 여기에는 수학적 함수 표현을 위한 몇가지 조건들이 있다. (퓨어함수라던가, 일차함수라던가 하는 함수형 프로그래밍에서의 함수 기본 조건은 설명된 다른 글들이 많으니 그건 여기서 스킵)

아래 수식을 프로그래밍해보면서 설명해보자

f(x)=x+1

위 함수는 입력된 값 x에 1을 더한 값을 반환하는 함수이다. 이걸 단순하게 코드로 치환하면 아래처럼 될거다.

fun f(x: Int) = x + 1

근데 우린 수학 함수를 변경하는 것이다. 수학에서는 또 아래같은 일이 발생한다.

x=2*z

x가 우리가 생각했던 것 처럼 하나의 값이 아닌 함수인 경우다. 그렇다 람다대수는 함수와 함수의 연산이다. 그래서 기본적으로 함수를 인자로 받을 수 있는 함수의 선언이 가능한 언어만이 함수형 프로그래밍을 지원할 수 있는 것이다. 그리고 우리도 함수의 파라메타를 함수로 받도록 함수를 작성해야 진짜 함수형 프로그래밍(람다대수가능 프로그래밍)을 한다고 볼 수 있다. 당연히 모든 함수 파라메타를 함수를 받도록 만드는 일은 어렵고 현실에서는 비효율적이거나 불합리할 수 있다. 가능한 파라메타 선언을 함수로 하는 것이 함수형 프로그래밍의 장점을 활용할 수 있다는 것 정도로 이해하자.

그래서 다시 아래 처럼 만들어질 수 있겠다.

fun f(x: (Int) -> Int) : (Int) -> Int = { x(it) + 1 }

fun xfunc(z: Int) = 2 * z

fun main(args: Array<String>) {
    println(f(::xfunc)(2)) //5
}

위의 것도 상황에 따라다를 수 있으니 일단 코드가 맞고 틀리고 보다는 어떻게 하는 것이 함수형 스럽게 만드는 것인지 이해하는데 집중하자.

함수형 프로그래밍에 필요한 함수 조건을 이해했으면 이와 연관되어 한가지 추론이 더 가능하다. 함수전달이 되어진다는 것은 값을 인자로 받는 것과 함수의 실행 시점의 시점이 변경됨을 알 수 있다. 그렇다 느낌이 온다. 함수형 프로그래밍을 통해 최종 연산되는 시점은 인자가 함수가 입력되는 시점이 아닌 leaf 함수에서 최종적으로 실제 값이 들어오는 시점이다. 일반적인 함수 실행 시점이 함수 호출 시점인 반면에 함수형 프로그래밍에서는 함수의 호출이 되더라도 인자가 값이 아닌 함수인 경우에는 해당 시점에 연산되지 않는다. 많이 들어본 lazy evaluation이 된다.

이렇게 함수형 프로그래밍이 가능한 언어는 최소한 함수를 인자로 받을 수 있는 함수 선언이 가능해야하고 lazy evaluation이 지원되야한다. 근데 지금 작성하고 보니 함수를 인자로 받을 수 있다는 것이 lazy evaluation을 지원 한다는 의미로 받아들여도 되지 않을까 한다.

함수형 프로그래밍은 수학수식으로 표현하기 위해 시작된 만큼 람다대수를 이해하는 것이 함수형 프로그래밍의 특장점을 살린 프로그래밍을 할 수 있는 것이라 생각된다. 사내에서 스터디중인 Haskell이 적응되면 될 수록, 함수형 프로그래밍의 장단점이 보이기 시작한다. 함수형 프로그래밍이 수학 함수의 표현을 위한 것이라고는 하지만 함수응용을 통한 프로그래밍이 가지는 프로그래밍적(?) 장점들이 있기에 이제는 꼭 수학 함수의 표현을 위해 프로그래밍 한다기 보다 함수형 프로그래밍의 장점때문에 함수형 프로그래밍이 인기가 있어진게 아닌가 생각된다.

프로그래밍 패러다임은 어느 것이 최고다라는 것이 없고, 내가 해결하려는 문제에 가장 적합한 패러다임인지에 대해서 평가한다. 다음 글에서는 내가 체득하고 있는 함수형 프로그래밍 패러다임의 장점들을 적어보고 어떤 상황에서 사용하면 좋은지에 대해 적어보겠다.