Skip to content

함수형 프로그래머가 되고 싶다고? (Part 4)

Hun-yong Song edited this page Oct 30, 2016 · 7 revisions

이 문서는 https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-3-1b0fd14eb1a7#.ii6um685m 를 번역한 내용입니다.

functinoal

함수형 프로그래밍 개념을 처음으로 접해본다는 것 자체가 중요하다. 그리고 이 단계가 가장 어렵기도 하다. 하지만, 올바른 관점으로 접근한다면 그렇게 어렵진 않다.

지난 글: 파트1, 파트2, 파트3

커링

puzzle

파트3를 기억한다면 mult5 함수와 add 함수를 합성할 때 문제가 발생했었는데, 그 원인은 mul5 함수는 1개의 매개변수를 받고, add 함수는 2개를 받기 때문이다.

우리는 모든 함수를 매개변수 1개만 받도록 제한함으로써 쉽게 이 문제를 해결할 수 있다.

믿어라. 생각보다 그리 나쁜 방법은 아니다.

우리는 2개의 매개변수를 받았던 add 함수를 1개만 받도록 간단하게 고친다. 커링 함수는 이걸 가능하게 해준다.

커링 함수는 한 번에 오직 1개의 매개변수만 받는 함수다.

이 개념은 mult5 함수와 합성하기 이전에 우리에게 add 함수의 첫번째 매개변수를 준다. 그리고 mult5AfterAdd10가 호출되면 add 함수는 두번째 매개변수를 받게 된다.

add 함수를 리팩토링하면서 커링 개념을 적용할 수 있다.

var add = x => y => x + y

이 버전의 add 함수는 처음에는 오직 하나의 매개변수만 받고, 나머지 한 개는 나중에 받는다.

조금 더 구체적으로, add 함수는 x라는 한 개의 매개변수를 받고, y라는 한 개의 매개변수를 받는 새로운 함수를 반환한다. 그 함수는 결과적으로 x와 y의 합계를 반환한다.

이제 우리는 이 버전의 add를 mult5AfterAdd10의 working version을 만들기 위해 사용할 수 있다.

var compose = (f, g) => x => f(g(x));
var mult5AfterAdd10 = compose(mult5, add(10));

compose 함수는 f, g라는 2개의 매개변수를 받는다. 그리고 x라는 1개의 매개변수를 받는 함수를 반환한다. 호출될 대 그 함수는 g 함수에 x를 적용한 후, 그 결과에 f를 적용한다.

여태 우리가 하고 있는 게 정확히 어떤 걸까? 평범한 예전 add 함수를 커링 버전으로 바꿨다. 이것으로 add 함수를 더욱 유연하게 만들었다. 왜냐하면 첫번째 매개변수 10은 상위 함수로 상속되고, 마지막 매개변수는 mult5AfterAdd10가 호출될 때 전달되기 때문이다.

이 부분에서 Elm에서는 add 함수를 어떻게 다시 작성하는지 아마 궁금할지도 모른다. 그럴 필요가 없는 게, Elm과 다른 함수형 언어에서는 모든 함수가 자동으로 커링되기 때문이다.

그래서 add 함수는 동일하게 생겼다.

add x y =
    x + y

이게 바로 파트3에서 mult5AfterAdd10가 작성 되었어야 할 모습이다.

mult5AfterAdd10 =
    (mult5 << add 10)

구문적인 면에서 Elm은 자바스크립트와 같은 명령형 언어를 이긴다. 왜냐하면 이 언어는 커링과 합성 같은 함수형 개념에 최적화 되어있기 때문이다.

커링과 리팩토링

baby

커링이 빛나는 또다른 경우는 리팩토링을 할 때다. 수많은 매개변수가 있는 일반적인 버전의 함수를 소수의 매개변수를 가진 버전으로 바꿀 때가 그 경우다.

예를 들어, 문자열에 1개의 중괄호 추가하거나 2개의 중괄호를 추가하는 함수가 아래에 있다.

bracket str =
    "{" ++ str ++ "}"
doubleBracket str =
    "{{" ++ str ++ "}}"

아래는 위의 함수를 실제로 사용한 예다.

bracketedJoe =
    bracket "Joe"

doubleBracketedJoe =
    doubleBracket "Joe"

우리는 bracket과 doubleBracket을 일반화 할 수 있다.

generalBracket prefix str suffix =
    prefix ++ str ++ suffix

하지만 이제 generalBracket을 사용할 때마다 중괄호를 넘겨줘야한다.

bracketedJoe =
    generalBracket "{" "Joe" "}"

doubleBracketedJoe =
    generalBracket "{{" "Joe" "}}"

What we really want is the best of both worlds. 우리가 정말 원하는 건 the best of both worlds이다.

If we reorder the parameters of generalBracket, we can create bracket and doubleBracket by leveraging the fact that functions are curried:

위키

기술 문서
Clone this wiki locally