커링(currying)

본문에서는 transfer 함수가 Account, Account, Int 타입의 인자 3개를 받고 IO () 리턴하는 함수로 설명했다. 이런 해석 방식으로도 하스켈 함수를 이해하고 사용하는 데에는 아무런 지장이 없지만 하스켈에서 ->을 보다 정확히 이해하기 위해서는 커링(curring)의 개념을 알아야 한다.

하스켈은 C/C++, 자바 등 일반적인 명령형(imperative) 언어와 달리 함수가 제 1 클래스이다. (파이썬과 루비 같은 최신 스크립트 언어는 예외다.) 여기서 제 1 클래스라고 하면 다른 타입과 마찬가지로 함수 역시 함수의 인자로 넘길 수 있고 리턴 값으로 함수를 리턴할 수도 있다는 뜻이다. 그리고 ->는 결합의 방향이 오른쪽이다.

따라서 Account -> Account -> Int -> IO ()는 실제로 (Account -> (Account -> (Int -> IO ())))를 뜻한다. 이렇게 괄호로 묶은 (Account -> (Account -> (Int -> IO ())))를 다시 보면 한 가지 흥미로운 사실을 발견할 수 있다. 이 함수는 Account 타입을 하나 인자로 받아서 (Account -> (Int -> IO ())) 타입의 함수를 리턴하는 함수로 볼 수도 있기 때문이다. 리턴된 함수의 타입인 (Account -> (Int -> IO ())) 역시 또 다른 Account를 인자로 받고 (Int -> IO ())를 타입으로 가지는 또 다른 함수를 리턴한다. 마지막으로 이 함수에 Int 인자를 넘기면 IO () 타입을 리턴한다.

즉, 우리가 처음에 3개의 인자를 받는다고 생각했던 transfer 함수는 실제로는 1개의 인자를 받는 여러 개의 함수로 이해할 수도 있다. 이처럼 여러 개 인자를 받는 함수를 1개의 인자를 받는 여러 함수로 변화시키는 것을 커링(currying)이라고 부른다.