Crossing borders

Posted 2008. 4. 30. 16:47
IBM dW의 연재 중에 Crossing borders는 프로그래밍 언어와 기술 간의 경계를 뛰어넘어 새로운 세계를 맛 보자는 뜻으로, 다양한 함수 언어를 소개하고 있습니다.

헤스켈 소개

Crossing borders: Explore functional programming with Haskell


얼랑 소개

Crossing borders: Concurrent programming with Erlang


비함수형 개발자에게 함수 언어의 개념을 소개하는 것은 비교적 쉽습니다만, 그 다음 단계인 함수 언어로 실제 어플리케이션을 작성하는 일과는 상당한 괴리가 있는 것으로 보입니다. 저 역시 함수 언어에 관심 갖고 공부해온 지가 꽤 오래되었지만 비교적 최근에서야 업무를 비롯해서 시험적으로 조금씩 써보는 정도거든요.

특히, 함수 언어를 실제 어플리케이션 작성에 쓰기 위해 반드시 풀어야할 문제는 IO, 외부 함수 호출, 동시성(concurrency) 등인 것 같습니다. Real World Haskell은 Haskell로 연습 문제만 풀지 말고 실제 어플리케이션을 작성할 수 있도록 가이드하자는 취지해서 작성되고 있는 책인데, 얼마나 성공적일지 지켜봐야겠습니다.


Memoization

Posted 2008. 4. 30. 01:51
순수(pure) 함수, 다른 말로 참조 투명한(referential transparent) 함수는 수학적인 함수와 마찬가지로 같은 인자를 넣으면 언제나 같은 값을 돌려줌을 보장하는 함수입니다. 간단한 예로, OCaml로 작성된 다음 피보나치 수열 함수(fib)는 참조 투명한 함수입니다.

let rec fib = function
    0 | 1 as i -> i
    | i -> fib (i - 1) + fib (i - 2)


위 fib 함수는 비효율적으로 작성되어 있기 때문에 무척 느립니다. 이런 순수 함수를 최적화하는 방법으로 알고리즘 자체를 꼬리 호출(tail recursion)하도록 변경하거나 더 나은 알고리즘을 찾는 방법 등도 있겠지만, 함수를 그대로 두고 메모리 공간을 희생해서 속도를 향상하는 최적화 방법으로 기억(memoization)이 있습니다.

다음 memo 함수는 Developing Applications With Objective Caml에서 발췌한 예입니다.

let memo f =
        let table = ref [] in
        let rec find_or_apply entries x =
            match entries with
                (x', y) :: _ when x' = x -> y
            | _ :: entries -> find_or_apply entries x
            | [] ->
                    let y = f x in
                    table := (x, y) :: !table;
                    y
        in
        (fun x -> find_or_apply !table x)

이 함수의 타입은

val memo : ('a -> 'b) -> ('a -> 'b)


로 원래 함수와 동일한 타입의 함수를 리턴합니다. 코드를 살펴보면 table을 두고 계산 결과를 저장해서 한 번 f(e) 값이 불리면 두 번째 불리는 f(e)는 새로 계산하지 않고 저장된 값을 쓰게 됩니다. 일종의 동적 프로그래밍(dynamic programming) 기법입니다.

기억(memorization)이 가능한 이유는 함수가 참조 투명하기 때문입니다. 매번 호출할 때마다 값이 바뀌는 함수라면 이전 함수의 결과를 저장해뒀다가 재활용하는 것이 불가능하기 때문입니다.

어느 정도 속도 향상이 있었는지 측정하기 위해서 시간을 재는 함수를 다음과 같이 만들어 봅니다.


let time f x =
    let start = Sys.time () in
    let y = f x in
    let finish = Sys.time () in
    Printf.printf "Elapsed time: %f seconds\n" (finish -. start);
    y
;;

OCaml은 함수 언어고 a + b라고 해서 a를 b보다 먼저 연산(evaluation)한다는 보장이 없습니다. IO의 경우는 순서가 중요하기 때문에, IO의 순서를 정하기 위해서 위와 같이 let 구문을 연달아 늘어 놓는 방법을 많이 씁니다. 앞서 let이 새로운 스코프(lexical scope)을 만들기 때문에 순서가 보장되게 됩니다.

let memo_fib = memo fib;;

time memo_fib 35;;
time memo_fib 35;;


fib를 memo로 감싸서 memo_fib 함수를 정의한 다음에 2번 불러보면 두 번째는 이미 계산된 저장 값을 가져 오기 때문에 매우 빠르게 계산됨을 확인할 수 있습니다.

Elapsed time: 2.579000 seconds
Elapsed time: 0.000000 seconds


자바 as 에스페란토 for JVML

Posted 2008. 4. 30. 00:15
전통적으로 프로그래밍 언어의 외부 인터페이스(외부 함수 호출)는 주로 C로 되어 있었습니다. 자바의 JNI(Java Native Interface)가 대표적이고, 파이썬도 Python/C API를 제공합니다. 함수 언어 OCaml로 C 인터페이스를 제공하고, Haskell도 마찬가집니다.

C는 프로그래밍 언어계의 에스페란토인 셈인데 C가 이렇게 널리 쓰이는 이유는 다음과 같습니다.

1. C는 표준화된 언어이다 (ISO C)
2. C는 운영 체제 구현 언어로 가장 많이 사용된다. 대표적으로, Unix, Windows, MacOS 등이 모두 C로 구현되어 있다.
3. 많은 라이브러리가 C로 구현되어 있다.
4. 대부분의 프로그래밍 언어가 C 인터페이스를 제공하기 때문에, 프로그래밍 언어가 C 인터페이스만 제공하면 다른 언어와 바인딩도 가능하다. 일례로, Pycaml은 OCaml C 인터페이스로 Python/C API를 호출해 파이썬을 바인딩한다.


자바 가상 머신에서 동작하는 언어에서는 자바가 C를 대체하는 새로운 에스페란토가 되고 있습니다. 자바는 앞서 C가 프로그래밍 언어 인터페이스로 많이 사용되는 이유가 모두 맞아 떨어집니다.


1. 자바는 표준화된 언어다 (Java Language Specification)
2. 자바는 자바 플랫폼 구현 언어로 사용된다. 자바 라이브러리는 모두 자바로 작성되어 있다.
3. 많은 라이브러리가 자바로 구현되어 있다.
4. 대부분의 JVML이 자바 인터페이스를 제공하기 때문에, 프로그래밍 언어가 자바 인터페이스만 제공하면 다른 언어와 바인딩도 가능하다.




« PREV : 1 : ··· : 5 : 6 : 7 : 8 : 9 : 10 : 11 : ··· : 82 : NEXT »