본문 바로가기

Better SW Development

[dW Review] 함수형 언어로 가는 길 (중편) - 일급객체


IBM dW 기사중에 바쁜 자바 프로그래머를 위한 스칼라 입문 이라는 멋지고 재미있는 연재글이 있습니다. 함수형 언어 중 하나인 스칼라에 대한 소개글인데, 바로 읽기에는 조금 어렵거나 지루할 수 있습니다. 특히나 처음 함수형 언어를 접하면 저와 동일하게 '으응? 뭐래?' 라는 식으로 제대로 읽기 어려울 것도 같다는 생각이 들었습니다. 관련해서 조금 돌아가지만 대신 차분히 접근할 수 있기 위해서 추가 글을 남겨봅니다. 군데군데 개인적인 사견이 많은 글이니 혹시라도 울컥!하진 마시고 적절히 걸러가면서 보세요. :)

이전글 : [dW Review] 함수형 언어로 가는 길 (상편) 

앞 글에서, 함수형 언어는 다루는 데이터를 훼손하지 않고, 배타적인 실행을 최대한 보장해 주기 때문에 스레드와 병렬처리에 장점을 갖는다고 했다. 장점은 알겠고, 언어적 특징은 어떠한가?

함수형 언어는 함수자체를 일급 객체(First-class object)로 간주한다.


[이게 집이야? 비행기 좌석이야?]

함수형 언어를 학습하기 시작하면 시점이 언제가 되었든 언젠가 한 번은 '일급 객체(First-class object)', 혹은 '일(등)급 시민(First-class citizen)'이라는 용어를 접하게 된다. 이 단어는 크리스토퍼 스트래치(Christopher Strachey)라는 영국 컴퓨터 과학자가 시대를 앞서 앞서 60년대에 만들어 낸 단어다. 그리고 두 단어는 동일한 의미로 사용된다.

어떤 객체(일반명사)가 있을때 다음 조건을 만족하면 일급 객체로 간주한다.

1. 변수나 데이터 구조안에 담을 수 있다.
2. 파라미터로 전달 할 수 있다.
3. 반환값(return value)으로 사용할 수 있다.
4. 할당에 사용된 이름과 관계없이 고유한 구별이 가능하다.

자, 그럼 자바를 기준으로 일급 객체는 무엇일까?

일반적인 자바 오브젝트는 1~4를 모두 만족시킬수 있다. 따라서 일급 객체가 된다. 그럼 자바에서의 함수, 즉 메소드는?
만족 안된다. 혹시라도 몇 개는 되지 않을까? 라고 생각할 수도 있지만, 미안. 안된다. 함수의 실행 결과는 만족시킬 수 있겠지만, 함수 그 자체는 일급객체로 쓰일 수 없다.

    ..
    return doSomething(a, b);
}
[위 코드를 함수를 넘기는 걸로 착각하는건 아니죠?]

함수가 일급 객체가 되려면 함수 자체를 파라미터로 넘기고, 결과값으로 함수가 오는 것이 가능해야 한다. 즉, 자바같은 명령형 언어에서는 안되지만 (일반적인) 함수형 언어는 함수(function)가 일급 객체 조건 네 가지를 만족시킨다.

예를 들면, 다음과 같은 두 가지 자바 함수가 있다고 가정해 보자.
 
DB 작업하기
dbWork( URL url, String qry ){
    connectToDB( url );
    sendQry( qry );
    closeFromDB();
}

네트워크 작업하기
networkWork( String serverIP, String msg ){
    connectToServer( serverIP );
    sendMessage( msg );
    disconnect();
}

두 작업은 하는일은 다르다. 하지만, 묘하게 비슷하다는 느낌이 든다. 그렇지만 하나로 합칠 수는 없다. 아니, 이렇게 두 코드를 함께 놓고 비교하는 이상한 상황이 아니라면 합칠수는 없을까 라는 생각 자체가 들지 않을 것이다. 혹여, 같이 놓고 본다고 해도 호출하는 함수나 넘겨주는 파라미터의 타입이 다르기 때문에 개운하진 않지만 방법이 없다는 결론에 이른다. 이게 함수를 일급 객체로 간주하지 못하는 명령형 언어의 한계다.


용사의 길, 마왕의 길. 시작과 끝은 다르지만 지나온 길은 같다.


[역할은 주인공인데 모습은 최종보스... 어쩌자는 거냐..]


앞의 두 메소드 코드 구조를 가상코드(seudo code)로 작성해 보자.

execute( setup, setupWith, do, doWith, after ){
    setup( setupWith );
    do( doWith );
    after();
}

이제는 위 코드를 마치 일종의 설계 템플릿이라고 자신을 세뇌해 보자. 그러면 다음과 같이 코드를 작성하는 모습이 상상가능하다.
execute( connectToDB, url, sendQry, qry, closeFromDB );
 
그리고 위와 같이 호출하면 아래와 같이 실행되었으면 좋겠다.
    connectToDB( url );
    sendQry( qry );
    closeFromDB();

네트워크 작업의 경우도 마찬가지로 적용해 보면 다음과 같다.
execute( connectToServer, serverIP, sendMessage, msg, disconnect );

역시 함수 이름을 파라미터로 넘기고 execute 메소드의 뼈대에 맞춰서 대치된다고 가정한다.
    connectToServer( serverIP );
    sendMessage( msg );
    disconnect();

위와 같은 방식이 가능만 하다면, execute 메소드 하나로 다양한 작업이 가능해 진다. 좀 더 상위 레벨 수준의 설계 템플릿을 만들어서 재사용이 가능해 진다. 이런식으로 프로그래밍이 가능하다면 코드 구조가 좀 더 유연해 질 수 있지 않을까?

가능하다. 함수형 언어에서는.

함수형 언어에서는 위와 같은 방식으로 구현하는 것이 가능하다.예제에서는 호출만 했지만, 원한다면 반환값으로 함수를 넘기는 것도 가능하다. 아래 예제에서는 이름없는(anonymous) 함수를 만들어서 넘긴 모습이다.

sum = (x, y) {
    return { x + y };
};

sum( 1, 2 );
[함수 그 자체를 변수에 할당해서 사용한다.]

물론 자바의 리플렉션을 사용하거나 루비의 메타프로그래밍을 이용하면 비슷하게 구현할 수 있다. 하지만, 부작용도 많고 무엇보다 프로그래밍 자체가 복잡해진다. 코드가 복잡해지는 건 앞에서 말했지만, 매.후. (오타아님) 나쁜일이다. 프로그래밍 언어는 사람을 좀 더 이해하기 쉽게 만드는 방향으로 발전해 나가고 있다는 걸 기억하자. 함수형 언어는 언어차원에서 함수를 일급객체로 다룰 수 있게 지원해 준다. 

이게 함수형 언어들이 갖는 제1 특징이다.

 (하편으로 계속)

- 예고 -
1. 왜 함수가 일급객체이여야 하나?
2. 함수형 언어의 다른 특징들과 병행성
3. 스칼라 vs 클로저