[Haskell] 01. 함수(Function)란?

먼저 시작하기 전에 함수(Function)에 대해 생각해보자.

사실 우리는 모두 중학교 수학에서 함수의 정의를 배웠다. 너무 오래돼서 기억이 안 날 수도 있고, 프로그래밍을 너무 오래 하다 보니 수학에서의 함수보다는 프로그래밍 언어에서의 함수에 익숙해진 지도 모른다. 프로그래밍에서의 함수와 수학에서의 함수가 개념적으로 같은 거 아니냐고 반문할 수도 있다. 둘은 비슷하지만 약간의 차이점이 있다.

먼저 어렸을 적 배웠던 수학에서의 함수를 생각해 보자.

\begin{equation}
y=f(x) \\
f:x \mapsto y
\end{equation}

언제 어디선가 본 기억이 어렴풋이 날 것이다. 뭔가의 \(x\)를 \(y\)로 연결해주는 \(f\)를 함수라고 불렀었다. 여기서 \(x\)는 입력이고 \(y\)는 출력이다. 함수형 프로그램밍(functional programming)은 이 3가지로 프로그램을 만드는 것이다. 간단하게 생각하면 간단하다. 입력 \(x\), 출력 \(y\), 그리고 그 둘을 이어주는 함수 \(f\).

조금 더 구체적인 예로 입력값의 제곱을 출력으로 내보내는 함수를 보자.

\begin{equation}
y=f(x) = \text{square}(x) = x^2 \\
\text{square}: x \mapsto x^2
\end{equation}

입력값 2를 받으면 4를 출력으로 내보낸다. 여기서 함수 \(f\)의 이름은 square가 된 것이다. 두 번째 표현 방식인 \(\text{square}: x \mapsto x^2\)를 잘 기억해 두기 바란다. Haskell에서 함수를 정의할 때 이와 같은 형식을 기반으로 한다. 이 함수를 아주 간단히 쓰면 다음과 같이 쓸 수도 있다.

\begin{equation} x \mapsto x^2 \end{equation}

필요 없는 것들은 다 제거하고 핵심만 남겼다. 다른 예도 비슷하다.

\begin{align}
x \mapsto x^2, \quad x \in \mathbb{Z} \\
x \mapsto 2x+3,\quad x \in \mathbb{N} \\
x \mapsto x^3+3x+5,\quad x \in \mathbb{R} \\
\end{align}

여기서는 \(x\)가 어떤 값을 갖는지 함께 나타내었다. \(\mathbb{Z}\)는 일반적으로 정수(Integer)를 나타내고, \(\mathbb{N}\)은 자연수 (1,2,3,…), \(\mathbb{R}\)은 실수를 나타내는 기호이다.

그럼 이런 함수가 다른 프로그램 언어에서의 함수와 어떤 점이 다른지 살펴보자.

int square(int x) {
    return x*x;
}

일반적인 C/C++ 에서의 함수이다. 다른 언어에서도 비슷한 형태를 가진다. 입력과 출력이 명확히 정의된다. 이런 함수를 순수 함수 (pure function)이라고 부르고, 위에서 언급한 수학에서의 함수와 같은 개념이다. 하지만 흔히 객체지향언어(Objective Oriented Language)에서 많이 쓰이는 멤버함수 (member function)을 보자.

double ratioHeightWeight() {
    return this->height/this->weight;
}

아마도 이 객체(Object)는 내부에 멤버변수로 height와 weight를 가지고 있을 것이다. 이런 함수의 형태는 객체지향언어에서 쉽게 볼 수 있는 형태의 함수인데, 입력이 명확히 정의되지 않는다. 아마도 생성자나 다른 함수를 통해서 height 값과 weight 값을 조절할 것이다. 이런 함수들을 impure function이라고 하고, 이 함수는 부작용(side-effect)을 갖는다고 표현한다. 입력과 출력에 관계없는 변수들이 함수 내부에서 어떤 짓을 할 수 있다는 의미이다. 사실 이런 함수 표현 방식 객체지향언어에서 핵심적인 역할을 한다. 변수를 객체 내부에 숨겨두고 정해진 interface를 통해서만 접근하도록 유도함으로, 객체 내부의 변수를 항상 유효한 상태로 유지한다. 하지만 함수형 언어에서는 이런 부작용을 용납하지 않는다. (불가능하다고 말할 수는 없다) 항상 입력, 출력, 함수 이 3가지만 생각하고, 같은 입력과 같은 함수는 항상 같은 출력을 갖는다.

이제 Haskell로 실습을 해보자!

Reply