스크립트 언어와 개발 도구(IDE)

Posted 2008. 11. 29. 23:09

마이크로소프트웨어 2008년 9월 박스 기사입니다.

흔히 스크립트 언어는 개발 도구 개발이 어렵다고 생각하는 사람이 많다. 동적 타입 시스템을 사용하는 스크립트 언어는 실행 전에 정확한 타입 정보를 알기 어렵기 때문이다. 예를 들어, MS 비주얼 스튜디오 인텔리센스(IntelliSense)는 자동으로 변수 혹은 함수 이름을 완성해주는 기능이다. 하지만 불행히도 스크립트 언어는 인텔리센스 같은 자동 완성 기능을 완벽히 지원하기 어렵다. 변수의 정확한 타입을 모르기 때문이다. 또 다른 예로, 리팩토링이 있다. 메서드 이름 변경 리팩토링을 했을 때 스크립트 언어는 메서드가 사용된 위치를 100% 정확히 파악할 수 없다.

 

하지만 개발 도구 지원이 약한 것이 반드시 언어 특징 때문은 아니다. 정적 타입 시스템을 사용하는 언어라고 크게 상황이 다르지 않기 때문이다. 예를 들어 자바는 정적 타입 시스템을 사용하지만 컴파일 타임에 모든 정보를 알 수 있지는 않다. 대표적인 예가 리플렉션(reflection)이다. 자바도 실행 시에 문자열로 메서드 이름이나 필드 이름을 참조할 있기 때문에 스크립트 언어와 마찬가지로 인텔리센스나 리팩토링 기능이 정확할 수 없다. 스크립트 언어 개발 도구가 미흡한 것은 아직 다른 언어처럼 개발 도구 개발에 많은 노력을 하지 않았기 때문으로 보는 것이 옳다.



웹 클라이언트 프로그래밍 언어

Posted 2008. 11. 29. 23:06

요즘은 자바 플랫폼과 .NET을 보면 다중 언어 지원이 대세다. 개발자가 하나의 프로그래밍 언어에 얽매여 있을 필요가 없는 시대가 왔다. 그런데 웹 클라이언트 프로그래밍만은 예외다. 어떤 개발자도 예외 없이 자바스크립트를 쓰도록 강요받고 있기 때문이다. 자바스크립트 나름의 매력에도 불구하고 웹 클라이언트 프로그래밍에 다른 언어를 쓰고자 하는 욕망이 있다 구글의 GWT, 280Slides의 Objective-J 등은 웹 클라이언트 프로그래밍에 각각 자바와 Objective-C라는 기존 언어를 쓰고자 하는 시도다. 이 글에서는 자바스크립트의 대안으로 사용되는 웹 클라이언트 프로그래밍 언어들을 살펴보려 한다.


마이크로소프트웨어 2008년 9월 기고글입니다.


새로운 웹 클라이언트 프로그래밍 언어


과거에는 프로그래밍 언어 하나로 전체 시스템을 만드는 방식이 일반적이었다. 하지만 스크립트 언어, 함수 언어 등의 필요성과 장점이 부각되면서 하나의 시스템을 만드는 데 여러 언어를 동시에 쓰는 방법이 인기를 얻고 있다. 예를 들어, 주요 컴포넌트는 자바로 작성하고 컴포넌트 통합 및 사용자 인터페이스 작성은 그루비로 하는 방식은 각 언어의 특징을 잘 살린 실용적인 접근법이다.

 

처음부터 다중 언어 지원을 중요한 기능으로 내세웠던 .NET은 현재 C#, VB.NET 외에도 IronPython, IronRuby, F#을 비롯해 수십 개의 프로그래밍 언어를 지원하고 있다. .NET에 대응하여 다빈치 머신(Davinci Machine) 프로젝트를 통해 다중 언어 지원을 강화하고 있는 자바 플랫폼도 그루비, Jython, JRuby, 스칼라 등의 자바가상머신 언어 개발을 적극적으로 후원하고 있다. 프로그래밍 언어의 중요 개발자들은 마이크로소프트와 썬 썬마이크로시스템즈가 영입해 개발 속도를 높이고 있다.

 

이런 변화의 바람 속에도 꿋꿋이 단일 언어만 고집하는 분야가 웹 클라이언트 프로그래밍이다. Ajax 바람 속에 웹 프로그래밍이 서버에서 클라이언트로 추가 넘어가고 있지만 자바, 파이썬, 루비를 포함한 서버의 다양한 개발 언어와 달리 클라이언트 프로그래밍은 오직 자바스크립트만이 유일한 대안이다. 대신 jQuery, Dojo, Prototype 등의 Ajax 라이브러리들은 각자의 취향에 따라 여러 속임수로 다른 언어를 흉내 내고 있다.

 

하지만 시간이 흐르면서 웹 클라이언트 프로그래밍에 새로운 언어들이 등장하기 시작했다. 대표 선수는 자바를 웹 프로그래밍에 사용한 구글의 GWT(Google Web Toolkit)다. 웹 프레젠테이션 도구인 280Slides 작성에 쓰인 Objective-J도 유명하다. 그 외에도 아직 프로토타입 수준이지만 루비, 파이썬 등 현존하는 거의 모든 언어가 모두 웹에서 돌아가는 시대가 열렸다.

 

이들 언어는 기존 웹브라우저에서 그대로 동작한다. 비법은 컴파일러에 있다. GWT의 경우 GWT 컴파일러가 자바로 작성된 소스 코드를 컴파일해서 자바스크립트를 생성한다. 일반적인 컴파일러는 고급 언어를 컴파일해서 중간 언어 혹은 기계 코드를 생성하는데 비해 웹 프로그래밍 언어 컴파일러는 최종 코드가 자바스크립트라는 차이만 있을 뿐 기본적인 컴파일러 동작 방식은 동일하다. 컴파일러 기술에 웹 클라이언트 프로그래밍 언어의 새로운 지평을 열었다.


GWT(Google Web Toolkit)


Ajax 프로그래밍은 구글의 대표 기술이다. 지메일(Gmail), 구글맵(Google Maps) 등 구글 대표 서비스는 Ajax 기술을 활용한 풍부한 사용자 인터페이스를 제공하였고 경쟁자들을 물리칠 수 있었다. 누구보다 자바스크립트를 많이 사용하는 구글이 자바스크립트가 아닌 자바로 웹 프로그래밍 툴킷을 제작했다. 구글이 밝힌 GWT의 장점은 컴파일러 최적화를 이용한 고성능 자바스크립트, 개발 도구 지원, 구글 API 및 재사용 UI 컴포넌트다.

 

GWT의 기본 가정은 손으로 작성한 자바스크립트 코드보다 자바로 작성한 후 컴파일러가 최적화하는 편이 성능이 더 좋다는 것이다. 물론 자바스크립트에 정통한 개발자는 최고의 성능을 발휘하는 아름다운 코드를 작성할 수도 있겠다. 하지만 C 언어가 아닌 어셈블리를 써야만 최고의 성능을 발휘할 수 있으니 무조건 어셈블리만 사용하자는 말과 동일하다. GWT는 자바 코드 컴파일해 얻은 자바스크립트 코드가 손으로 작성한 자바스크립트 코드보다 더 빨리 로딩되면서 코드 크기는 오히려 작다고 이야기한다.

 

이식성도 중요한 이유다. 자바스크립트는 이식성이 나쁜 언어다. 웹브라우저마다 자바스크립트 인터프리터, DOM, 이벤트 등이 미묘하게 다르고 브라우저 간 호환성을 위해서는 상당한 노력이 필요하다. 물론 고급 Ajax 라이브러리가 이 문제를 상당히 해결한 것은 사실이지만 GWT는 이 문제를 더 높은 수준에서 해결했다. GWT 개발자는 GWT 개발 환경 하나만 익히면 모든 브라우저에서 호환되는 코드를 자동으로 만들 수 있게 된다.

 

GWT가 자바를 선택한 또 다른 이유는 개발 도구 지원이다. 자바는 이클립스(Eclipse)라는 세상에서 가장 강력한 개발 도구를 보유한 언어이다. 물론 개발자 개인 취향에 따라 IntelliJ 혹은 NetBeans를 선택할 수도 있다. 반대로 자바스크립트는 개발 도구 지원이 열악하다. 동적 타입 시스템을 쓰는 스크립트 언어 특징상 개발 도구 개발이 어렵기 때문이다. 크고 복잡한 응용 프로그램 개발의 경우 개발 도구 지원 여부는 프로그래밍 언어 선택의 중요 기준이 된다.

 

GWT은 재밌는 기능 중 하나는 JSNI(JavaScript Native Interface)이다. 원래 자바는 JNI(Java Native Interface)라고 해서 자바로 작성된 프로그램이 C 함수를 호출할 수 있는 인터페이스를 열었다. GWT는 웹 브라우저에서 돌아가는 코드를 생성하므로 C 코드를 호출할 수는 없는 대신 자바스크립트 코드를 호출할 수 있게 했는데 그 인터페이스가 JSNI다. 특정 브라우저에만 있는 기능을 이용하거나 GWT가 생성한 코드보다 더 효율적인 코드를 자바스크립트로 작성할 수 있다고 판단했을 때 쓰면 된다.

 

GWT를 사용한다고 모든 자바 프로그램이 웹에서 실행되지는 않는다. GWT는 자바 언어를 사용하지만 JRE(Java Runtime Environment)를 모두 제공하지는 않기 때문이다. GWT는 JRE의 일부를 웹으로 포팅했고 웹 프로그래밍을 위한 별도의 API를 제공한다. 또한 UI를 쉽게 만들 수 있도록 기존 스윙(Swing) 혹은 SWT와 유사한 UI API도 제공한다. UI 렌더링을 할 때는 HTML을 동적으로 생성하여 붙이는 방식을 쓴다.


Objective-J



Objective-J를 이용해 만든 프레젠테이션 도구 280slides


GWT가 데스크톱 프로그래밍의 일부를 웹 프로그래밍에 도입한 프로젝트라면 Objective-J와 Cappuccino는 데스크톱 프로그래밍 환경을 웹에 그대로 옮겨놓은 야심찬 프로젝트다. Objective-J는 그 이름에서 알 수 있듯이 Mac OS X 데스크톱 응용 프로그램 개발에 사용되는 Objective-C를 웹으로 옮겨놓은 버전이다. Objective-J를 만든 North280은 웹 프레젠테이션 도구(MS의 파워포인트, 애플의 키노트)인 280Slides 통해 Objective-J의 가능성을 보여줬다. Cappuccino는 Mac OS X UI 라이브러리인 Cocoa를 웹으로 포팅한 것이고 역시 North280 팀이 만들었다.

 

웹 프로그래밍 하면 떠오르는 모습은 Rails, Django 등의 웹 프레임워크로 서버 측 프로그램을 작성하고 HTML, CSS, Ajax 라이브러리로 클라이언트 프로그램을 만드는 방식이다. 하지만 서버 쪽 코드를 줄이고 데스크톱 응용 프로그램과 유사한 웹 응용 프로그램을 만들려는 시도도 계속되고 있다. 대표적인 예가 SproutCore이다. 플래시나 실버라이트가 표방하는 리치 클라이언트(rich client)의 자바스크립트 버전인 셈이다. SproutCore 프로그램은 대부분의 시간을 웹 서버와 독립적으로 동작하다가 데이터를 저장하거나 불러올 때만 Ajax 라이브러리로 서버와 통신하는 방식을 사용한다. SproutCore로 작성된 프로그램은 Rails 웹 응용 프로그램보다는 데스크톱 Cocoa 프로그램을 더 닮았다.

 

이런 변화의 바람 속에서 웹 프로그램이 Rails 보다 Cocoa 프로그램을 더 닮았다면 자바스크립트가 아닌 Objective-C로 코딩하자는 생각에서 출발한 프로젝트가 Objective-J다. Objective-J의 예는 프로그래밍 언어는 단순한 문법이 아니라 그 언어를 사용하는 사람, 문화, 기술을 통칭함을 보여준다. Objective-J 도입은 자바스크립트, CSS, HTML, DOM을 이용한 전통적 웹 응용 프로그램 개발 방식을 대체하는 데스크톱 스타일의 개발 환경을 웹으로 가져온다.

 

Objective-J는 North280 팀에 의해 조만간 오픈소스화될 예정이다. Objective-J (http://objective-j.org/) 홈페이지를 확인해 보기 바란다.


Flapjax


앞서 언급한 GWT나 Objective-J는 기존 프로그래밍 언어를 웹으로 포팅하고 각 언어의 장점을 살려 데스크톱 응용 프로그램을 쉽게 구축할 수 있는 방법을 제공했다. 반면에 Flapjax는 새로운 웹 프로그래밍 모델을 제시하는 프로그래밍 언어다.

 

자바스크립트 프로그래밍의 문제점 중 하나는 콜백 함수 등록이 너무 많다는 점이다. 마우스 위치를 따라 네모 박스가 약간 시간 간격을 두고 따라오는 간단한 자바스크립트 프로그램을 생각해보자. 다음과 같은 HTML, 자바스크립트 코드가 필요할 것이다.


<div id="box" style="position:absolute; background:yellow;">

     Seconds to deadline: <span id="time">...time...</span>

</div>

<script>

 

document.addEventListener(

     'mousemove',

     function(e) {

         var left = e.pageX

         var top = e.pageY

         setTimeout(function() {

             document.getElementById("box").style.top = top;

             document.getElementById("box").style.left = left;

         }, 500);

     }, false);

</script>

자바스크립트 예제


자바스크립트 프로그래밍에 익숙한 개발자는 위 코드가 직관적이라고 느낄 수도 있겠다. 하지만 마우스 위치에 따라 네모 상자를 옮기는 간단한 일을 하기 위해 콜백을 2번 등록하고 "box" ID를 찾아서 값을 변경해야 한다. 가독성도 떨어진다. 이 프로그램은 마우스의 움직임에 따라 다음 그림과 같은 명확한 데이터 흐름이 있지만 위 자바스크립트 소스 코드만 보고 이 사실을 한 번에 알아내기는 쉽지 않다.


데이터 흐름도(data flow)


Flapjax는 이처럼 자바스크립트(Ajax) 프로그램에서 빈번히 발생하는 데이터 흐름 중심으로 프로그램을 기술하는 언어다. 위 프로그램은 Flapjax로 작성하면 다음과 같다. Flapjax는 자바스크립트와 유사한 문법을 가지며 자바스크립트로 컴파일된다.

 

<div style={!

     {

         position:"absolute", background: "yellow",

         top: delay(mouseTop(), 500),

         left: delay(mouseLeft(), 500)

     }

!}

> Seconds to deadline: {! timeStream() !}. </div>

Flapjax 예제 (주의: 설명을 위해 간단하게 만들었기 때문에 실제 동작하지 않음)


이 프로그램을 해석하는 방법은 간단하다. mouseTop()과 mouseLeft()는 지속적으로 현재 마우스의 위치를 주는 데이터 소스로 생각하면 된다. top 값은 mouseTop 값이 바뀜에 따라 지속적으로 변경되는데, 변경 시에는 500ms의 지연이 있다. 마찬가지로 left 값은 mouseLeft() 값이 바뀜에 따라 지속적으로 바뀌고 500ms의 지연이 있다. timeStream()은 흐르는 시간을 데이터 소스로 주기 때문에 화면에 표시되는 시간이 계속 바뀐다.

 

Flapjax는 지속적으로 값이 변경되는 데이터 소스가 존재하고 이 값이 변하면 여기에 의존하는 값들이 자동으로 변경되는 방식을 채택했다. 따라서 일반적인 자바스크립트 프로그래밍처럼 변경이 예상되는 이벤트에 일일이 콜백을 걸어줄 필요 없이도 자동으로 새로운 값이 계산된다. Flapjax 프로그래밍 모델에서는 데이터 흐름이 명시적으로 보이는 것이 장점이고 document.getElementByID를 이용해 변경할 노드를 찾을 필요 없을 값을 삽입할 위치에 직접 코드를 적어주면 된다.



핫루비(HotRuby)


컴파일러 외에 웹에서 다중 언어를 구현하는 또 다른 방식은 자바스크립트로 가상 머신을 구현하는 것이다. 예를 들어 자바가상머신(JVM)을 자바스크립트로 작성하면 자바 프로그램을 바이트코드로 컴파일한 후에 자바스크립트로 돌릴 수 있다. 물론 가상머신은 보통 성능을 높이기 위해 효율적인 C/C++ 코드로 작성하는 것이 일반적이지만 이론적으로는 자바스크립트로 작성해도 아무런 문제가 없다.

 

핫루비 프로젝트는 루비 인터프리터를 자바스크립트로 구현하는 프로젝트다. Ruby 1.9 YARV(Yet Another Ruby VM)의 바이트코드 인터프리터를 만들었다. <script type="text/ruby"></script> 태그 안에 루비 코드를 작성해 넣으면 텍스트를 뽑아서 XMLHttpRequest로 서버에 보낸다. 서버 CGI는 루비 코드를 받아서 바이트코드로 바꾸고 직렬화해 JSON으로 보낸다. 브라우저는 루비 인터프리터를 돌려서 루비 코드를 실행한다. 핫루비는 기존 코드를 재활용하기 위해 루비 컴파일러를 서버에 두는 방식을 택했지만 이론적으로는 루비 컴파일러 또한 자바스크립트로 만들어 넣을 수 있다.

 

존 레시그(John Resig)는 다음 코드로 핫루비의 성능을 측정했다[3]. 벤치마크 결과 Ruby 1.8.2에서는 12.25초가 걸렸다. 자바스크립트로 구현한 핫루비의 성능은 어느 정도 일까? 놀랍게도 파이어폭스 2에서 6.71초, 파이어폭스 3.0b5에서 2.47초 만에 수행이 끝났다. C로 구현한 Ruby 1.8.2 보다 자바스크립트로 구현한 핫루비가 몇 배나 더 빠른 셈이다. 게다가 파이어폭스 버전이 올라갈수록 더 빨라지고 있다.


startTime = Time.new.to_f

sum = ""

50000.times{|e| sum += e.to_s}

endTime = Time.new.to_f

puts (endTime - startTime).to_s + ' sec'

루비 벤치마크


["YARVInstructionSequence\/SimpleDataFormat",1,1,1,{"arg_size":0,"local_size":4,"stack_max":3},"","src","top",["startTime","sum","endTime"],0,[["break",null,"label_21","label_29","label_29",0]],[2,["putnil"],["getconstant","Time"],["send","new",0,null,0,null],["send","to_f",0,null,0,null],["setlocal",4],4,["putstring",""],["setlocal",3],"label_21",5,["putobject",50000],["send","times",0,["YARVInstructionSequence\/SimpleDataFormat",1,1,1,{"arg_size":1,"local_size":1,"stack_max":2},"block in ","src","block",["e"],[1,[],0,0,-1,-1,3],[["redo",null,"label_0","label_22","label_0",0],["next",null,"label_0","label_22","label_22",0]],["label_0",5,["getdynamic",3,1],["getdynamic",1,0],["send","to_s",0,null,0,null],["send","+",1,null,0,null],["dup"],["setdynamic",3,1],"label_22",["leave"]]],0,null],"label_29",["pop"],7,["putnil"],["getconstant","Time"],["send","new",0,null,0,null],["send","to_f",0,null,0,null],["setlocal",2],9,["putnil"],8,["getlocal",2],["getlocal",4],["send","-",1,null,0,null],["send","to_s",0,null,0,null],["putstring"," sec"],9,["send","+",1,null,0,null],["send","puts",1,null,8,null],8,["leave"]]]

서버가 생성해 JSON으로 준 핫루비 바이트코드


상식적으로 납득하기 어려운 벤치마크 결과를 설명하기 위해서는 Ruby 1.8.2와 Ruby 1.9의 차이를 알아야 한다. Ruby는 인터프리터가 비효율적인 것으로 유명한 스크립트 언어다. 동일한 일을 수행하는 코드를 작성하면 C 보다 100배 이상 느린 경우가 다반사다. 파이썬이 소스코드를 일단 중간 코드(바이트코드)로 변환한 후에 인터프리트하는 것과 달리 루비는 1.8.2까지 파싱된 소스 코드(AST)를 매번 새로 방문하면서 코드를 실행하는 방식을 택했기 때문이다. YARV는 이런 문제를 해결하기 위해 루비에 바이트코드 인터프리터를 추가하는 프로젝트였고 루비 1.9는 YARV를 기본으로 채택했다. 핫루비는 바이트코드 인터프리터이기 때문에 루비 1.8.2의 비효율적인 실행 방식에 비해 빠르다.

 

핫루비의 성능이 괜찮은 또 다른 요인은 자바스크립트 인터프리터가 점점 빨라지고 있다는 점이다. 파이어폭스 2.0과 3.0b5의 비교를 해보면 3.0b에서 2.71배 속도 향상이 있음을 볼 수 있다. 앞서 언급한 GWT, Objective-J 등 대형 Ajax 프레임워크가 나오면서 자바스크립트 속도 향상이 브라우저 벤더들 사이에서 중요한 요구사항이 되었기 때문이다.

 

모질라는 파이어폭스의 성능을 더 높이기 위해 현재 아도브가 기증한 타마린(Tamarin) 스크립트 엔진을 파이어폭스 스크립트 엔진인 스파이더몽키(SpiderMonkey)에 붙이는 액션몽키(ActionMonkey) 프로젝트를 진행하고 있다. 그것만으로 모자랐는지 아도브는 타마린에 바이트코드 실행 기록을 남겨서 머신 코드를 생성하는 트레이스 JIT를 추가한 타마린 트레이싱(Tamarin Tracing)까지 내놓고 자바스크립트 속도를 높이기 위해 안간힘을 쓰고 있다.

 

이런 움직임은 애플 사파리에서도 마찬가지다. 애플은 최근 레지스터 바이트코드를 쓰는 다이렉트 쓰레드(direct-threaded) 코드 기반의 효율적인 자바스크립트 엔진 인터프리터인 스쿼럴피시(SquirrelFish)를 내놨고, 그 속도는 JIT 컴파일러를 내장한 타마린을 능가하고 있다. 스쿼럴피시는 앞으로 사파리에 탑재되어 데스크톱 사파리와 iPhone 사파리 모바일 등에 사용될 예정이다.


정리


웹 프로그래밍은 서버에서 클라이언트로 이동하고 있다. 플래시, 실버라이트, JavaFX 등 비표준 RIA 플랫폼 이런 변화를 앞당긴 기술이다. 웹 표준 기반 응용 프로그램도 서서히 서버에서 클라이언트로 방향 전환을 하고 있다. 따라서 Ajax로 대표되는 웹 클라이언트 프로그래밍의 중요성이 날로 커지고 있다.

 

앞서 살펴본 것처럼 웹 클라이언트 프로그램이 발전하고 데스크톱 응용 프로그램과 유사한 기능을 원하게 되면 기존 데스크톱 응용 프로그램에 작성에 사용되는 프로그래밍 언어와 라이브러리들이 웹으로 진입할 가능성이 크다. 컴파일러 혹은 VM 기술에 힘입어 기존 브라우저를 수정하지 않고도 다양한 언어를 지원할 수 있기 때문이다.

 

따라서 앞으로 웹 개발자는 빠르고 효율적인 개발을 위해 서버 기반 웹 프레임워크에서 벗어나 클라이언트 솔루션을 찾아볼 필요가 있다. GWT, Objective-J, Flapjax 등의 새로운 웹 프로그래밍 언어 및 프레임워크는 웹 응용 프로그램 작성에 있어 든든한 지원군이 되어줄 것이다.


참고문헌


[1] GWT(Google Web Toolkit) Documentation

http://code.google.com/webtoolkit/overview.html

 

[2] Flapjax Tutorial

http://www.flapjax-lang.org/tutorial/

 

[3] Ruby VM in JavaScript

http://ejohn.org/blog/ruby-vm-in-javascript/














하스켈의 IO

Posted 2008. 11. 29. 04:34

마소 4월호 박스 기사입니다.


스켈은 순수 함수형 언어이며 원칙적으로 사이드 이펙트가 없다. 여기서 사이드 이펙트는 프로그램 수행의 결과로 상태가 변화하는 경우를 일컫는다. 대표적인 사이드 이펙트는 IO로, 화면에 결과를 출력하거나 키보드로부터 입력을 받는 일을 말한다. 간단한 예로 putStr 함수는 문자열을 받아서 화면에 출력해주며 타입은 다음과 같다.

 

putStr :: String -> IO ()

putStr의 타입


putStr은 String을 인자로 받고 IO를 수행한 후에 ()를 리턴한다는 뜻이다. 또 다른 예로 getLine을 사용자에게 한 줄 입력을 받는 함수며 타입이 다음과 같다.


getLine :: IO String

getLine의 타입


getLine은 인자가 없고 IO를 수행 후에 String 타입을 리턴한다. do {}를 사용하면 이렇게 IO를 수행하는 함수를 통해 조금 더 복잡한 일을 순차적으로 수행할 수 있다. 앞서 소개한 두 함수를 조합해 사용자가 한 줄 입력을 받은 후에 그대로 보여주는 프로그램은 다음과 같다.


echo :: IO ()

echo = do { s <- getLine

                ; putStr s }

echo 함수



파이썬 구현들

Posted 2008. 4. 30. 21:05
흔히 파이썬하면 파이썬 언어 명세보다는 Guido van Rossum이 작성한 CPython을 의미하는 경우가 많습니다. 하지만 CPython 외에도 파이썬을 구현한 프로젝트가 많이 있었습니다. 한 때 많은 사람들의 관심을 받았던 Stackless Python을 필두로 시작된 파이썬 구현은 현재 JVM과 .NET에 올라간 Jython, IronPython으로 이어지고 있습니다. 파이썬으로 파이썬을 구현하자는 PyPy 프로젝트도 있습니다.

더 이상 개발되지는 않지만 실험적인 파이썬 구현으로는 PyVM과 Vyper가 있었습니다. 그 중 Vyper는 John Max Skaller OCaml로 작성한 파이썬 구현입니다. 당시 파이썬 스코핑(scoping) 룰에 불만을 품고 시작해 좀 더 빠르고 함수적인 파이썬을 만들려는 시도였습니다. IBM dW에 보면 Stackless Python의 Christian Tismer와 Vyper의 John Max Skaller와 인터뷰가 있더군요. 하지만 지금은 Vyper의 홈페이지 링크조차 깨진 채 존재하지 않는군요. 아아. Vyper가 커뮤니티의 도움을 얻어 CPython과 더불어 성장해줬다면 조금 더 함수형인 파이썬이 나왔을지도 모르겠습니다.

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이 자바 인터페이스를 제공하기 때문에, 프로그래밍 언어가 자바 인터페이스만 제공하면 다른 언어와 바인딩도 가능하다.




OCaml 프로그램 최적화

Posted 2008. 4. 29. 20:45
프로그래밍 언어를 공부를 단계별로 나눈다면

(1) 프로그래밍 언어의 문법를 파악
(2) 프로그래밍 언어의 의미(semantics)를 이해
(3) 프로그래밍 언어 커뮤니티가 사용하는 관례와 용법 파악
(4) 프로그래밍 언어 내부 구현(컴파일러, 인터프리터) 지식을 활용한 최적화 코드 작성

정도의 순서로 진행될 것입니다. OCaml은 일반적으로 상당히 빠른 머신 코드로 컴파일될 수 있다고 알려져 있지만 OCaml 컴파일러가 어떤 최적화 기법을 사용하는지 알면 더욱 더 효율적인 코드를 짤 수 있을 것입니다. 

예를 들어, 다중 인자를 받는 OCaml 함수를 정의할 때 두 가지 방법을 사용할 수 있습니다. OCaml QnA의 Making code run fast라는 글에서 인용했습니다.

fun x y z -> ...


fun (x, y, z) -> ...


첫 번째는 커리(curried) 형태이고, 두 번째는 언커리(uncurried) 함수로 여러 인자를 하나의 튜플로 만든 형태입니다. 

개발자가 느끼기에 두 코드가 하는 일은 거의 동일하지만 OCaml 컴파일러 입장에서 봤을 때는 달라지는 부분이 생깁니다. OCaml 바이트코드 컴파일러(ocamlc)의 경우, 커리 함수는 힙(heap) 할당 없이 스택에 변수를 넘겨서 함수 호출을 수행함을 보장합니다. 반대로 언커리 함수는 힙에 튜플을 만들어서 넘깁니다. 호출된 함수 안에서는 다시 튜플에서 각각의 원소를 꺼내 와야 하기 때문에 커리 함수에 비해 속도가 느려집니다.

그런데 반드시 이렇게 되어야만 하는 것도 아닙니다. 네이티브 컴파일러(ocamlopt)는 두 경우 모두 힙에 할당하지 않고 레지스터를 이용해 파라미터를 전달하기 때문에 두 함수는 성능 차가 없어집니다.

또 하나의 예로, 대부분의 Lisp이나 ML 컴파일러는 부동소수점 계산이 느립니다. 가비지 콜렉션, 다형성/타입 추상화 등 때문에 부동소수를 힙에 할당하고 포인터를 저장하는 방식으로 구현된 경우가 많기 때문입니다. float 두 개 더하려면 포인터를 2개 읽어서 float를 가져와 더한 다음에 그 결과를 다시 포인터가 가리키는 주소에 저장해야 하기 때문에 속도가 느려질 수밖에 없습니다.

컴파일러가 부동소수점을 언박싱(unboxing)하는 최적화를 하면 이 문제를 완화시킬 수 있습니다. 다만 컴파일러가 모든 케이스를 자동으로 언박싱할 수 없기 때문에 몇 가지 트릭을 사용하게 되고, 이런 트릭을 모르는 개발자는 속도가 느린 프로그램을 작성할 수밖에 없게 되는 것이죠.

예전에 조엘(Joel) 아저씨가 "The Law of Leaky Abstraction"을 이야기했는데 그 말이 딱 맞아떨어지는 부분입니다. 프로그래밍 언어를 추상화시켜서 내부 구현을 모르도록 만들어놨지만 결국 제대로 사용하려면 내부 구현을 상당 부분 알아야 한다는 것이죠.


GODI

Posted 2008. 4. 29. 20:02
OCaml의 라이브러리(표준 라이브러리 제외)는 GODI 프로젝트를 통해 관리되고 있습니다. GODI 툴 체인(godi_console)을 사용하면 OCaml 라이브러리를 쉽게 설치/제거할 수 있습니다. GODI 라이브러리 목록은 camlcity.org 홈페이지에 링크되어 있는데,  생각보다 별로 많지 않은 것 같네요. Perl의 CPAN와 비교하면 약간 부끄러울 정도랄까요? godi_console로 확인해보니 164개의 라이브러리가 있군요.

GODI로 설치된 OCaml 라이브러리는 다음과 같이 로딩합니다. 예를 들어, Bitmatch라는 라이브러리 로딩하려면 다음과 같이 합니다.


skyul@skyul-desktop:~$ ocaml
        Objective Caml version 3.10.1
# #use "topfind";;
- : unit = ()
Findlib has been successfully loaded. Additional directives:
  #require "package";;      to load a package
  #list;;                   to list the available packages
  #camlp4o;;                to load camlp4 (standard syntax)
  #camlp4r;;                to load camlp4 (revised syntax)
  #predicates "p,q,...";;   to set these predicates
  Topfind.reset();;         to force that packages will be reloaded
  #thread;;                 to enable threads

- : unit = ()
# #require "Bitmatch";;
No such package: Bitmatch
# #require "bitmatch";;
/opt/godi/lib/ocaml/site-lib/bitmatch: added to search path
/opt/godi/lib/ocaml/site-lib/bitmatch/bitmatch.cma: loaded
# open Bitmatch;;
# Bitmatch.create_bitstring 10;;
- : Bitmatch.bitstring = ("\000\000", 0, 10)

OCaml 죽이기

Posted 2008. 4. 29. 00:57
OCaml 프로그램은 이론적으로 절대 크래시가 날 수 없습니다. 외부 모듈(C로 작성된 코드)를 호출한 경우가 아니면 죽을 수가 없게 타입 시스템 자체가 디자인되었기 때문입니다.

하지만 강한 타이핑(strong typing)하는 언어라도 직렬화(OCaml에서는 Linearization 용어 사용, 자바의 Serialization과 같은 개념)를 지원하면 타입 시스템을 얼마든지 깨먹을 수 있게 됩니다. OCaml은 Marshal 모듈을 사용해 직렬화를 하는데, Marshal 모듈을 이용하면 다음과 같이 'a 타입을 'b 타입으로 강제로 바꾸는 함수(C의 캐스팅)를 작성할 수 있습니다.


# let magic_copy a =
    let s = Marshal.to_string a [Marshal.Closures] in
        Marshal.from_string s 0;;
val magic_copy : 'a -> 'b = <fun>


이렇게 작성한 후에 다음과 같이 int 타입을 float로 강제로 변환한 후에 덧셈을 하면 크래시가 발생하고 프로그램이 죽게 됩니다.

# (magic_copy 2 : float)  +. 4.5;;
Segmentation fault



프로그래밍 언어 성능 측정

Posted 2008. 4. 28. 20:40
프로그래밍 언어의 특성 중 실용적인 관점에서 가장 중요한 요소 중 하나는 성능입니다. 요즘 동적 언어가 인기를 얻는 것을 보면 생산성이 성능보다 더 높은 점수를 얻고 있는 것 같긴 하지만, Python이나 Ruby를 .NET이나 JVM으로 포팅해서 HotSpot이나 JIT을 이용하려는 시도는 성능은 여전히 중요한 요소임을 반증합니다. (물론 .NET이나 JVM의 방대한 라이브러리를 재활용하고 다른 언어로 작성된 프레임워크를 사용하려는 목적도 큽니다.)

프로그래밍 언어 자체의 성능은 비교할 수가 없습니다. C 언어라도 컴파일러가 거지같으면 굉장히 느릴 수 있고, 옛날에 느리다고 욕먹던 Java도 근래 많은 최적화를 한 서버 JVM을 사용하면 C/C++과 유사한 정도로 성능이 올라가기도 하니깐요. 따라서 프로그래밍 언어 보다는 프로그래밍 언어의 구현을 놓고 성능을 비교해야 합니다.

그런데 벤치마크라는 게 컴파일러나 인터프리터 몇 개 갖다 놓으면 바로 비교가 되는 것이 아니고 또 별도의 벤치마크 프로그램을 통해 간접적으로 테스트해야만 합니다. 어떻게 벤치마크 할 것이냐를 놓고 이견이 많고 시끄러울 수밖에 없습니다. 어떤 언어는 과학 연산만 죽어라고 하는 벤치마크에는 매우 취약한 반면에 문자열 연산이 많은 벤치마크에는 좋은 성능을 보여줄 수도 있으니깐요.

어느 정도 신빙성이 있는지는 모르겠지만, Debian에서 프로그래밍 언어를 비교하는 벤치마크를 하나 제공하고 있습니다. The Computer LanguageBenchmarks Game인데, Gentoo나 Debian이 깔린 리눅스 머신에서 몇 가지 벤치마크의 성능을 순서대로 보여줍니다. 모든 벤치마크를 모든 언어에 대해 돌려보니, Java 6 -server의 성능이 인상적이고, 함수 언어인 Clean, Haskell GHC, OCaml 등도 상당히 좋네요.

IBM dW의 Crossing borders: Typing strategies beyond the Java model는 프로그래밍 언어의 타이핑 전략(typing strategies)에 대해서 이야기하고 있습니다. 상당수 개발자들이 프로그래밍 언어의 타이핑 생산성, 유지보수성 등에 상당한 영향을 미친다고 생각하고 있고, 자바 개발자들이 상당수 루비로 갈아탄 것도 이와 무관하지 않아 보입니다.

이 기사의 저자는 자바 타이핑에 대한 대안으로 서로 양극단에 있는 Ruby와 OCaml의 타이핑을 비교하고 있습니다. Ruby는 동적 타이핑을 하는 대표적 언어이고, OCaml은 정적 타이핑의 대표 주자인 ML 계열의 언어입니다.

프로그래밍 언어의 타이핑을 구분하는 방법은 몇 가지가 있는데, 정적/동적 타이핑, 강한(strong)/약한(weak) 타이핑이 일반적인 구분 방법입니다. 여기에 하나 덧붙이자면 명시적/암묵적 타이핑이 있습니다. 명시적 타이핑 언어는 자바나 C#처럼 모든 타입을 개발자가 적어줘야 하는 방식이고, 암묵적 타이핑은 OCaml이나 Haskell처럼 개발자가 일부 타입을 기입하지 않더라도 타입 추론을 통해 컴파일러가 나머지 타입을 찾아내는 방식입니다.

자바가 루비에 비해 생산성이 떨어지는 문제를 동적/정적 타이핑의 문제로만 볼 수 없는 이유는 자바와 OCaml을 비교했을 때 자바 이상으로 강력한 정적 타이핑을 제공하는 OCaml 코드가 자바보다는 루비에 가까운 간결함을 보이기 때문입니다.

근데 하나 분명한 것은 자바는 아니라는 것입니다. 루비도 좋고 OCaml도 좋고 장단점이 있지만 명시적 정적 타이핑하는 자바는 이제 수명이 다하고 있다는 것이 핵심이 아닐까 싶습니다. Spring, AspectJ, Hibernate 등 다양한 자바 기반의 거대 프레임워크가 존재하는 이유는 반대로 생각하면 자바만으로는 일반적인 어플리케이션 개발에 요구되는 메타프로그래밍을 쉽게 할 수 없기 때문입니다.

물론 워낙 개발자가 많은 자바 진영이다 보니 그리 쉽게 망하겠냐는 생각을 하실 수도 있겠지만, 자바를 다른 언어로 대체하려는 움직임은 자바 진영 내부에서 가장 먼저 논의되고 있습니다. 요즘은 JVM에서 동작하는 언어(JVML)에 대한 이야기로 뜨겁습니다. 함수 언어와 객체지향 언어를 결합한 Scala가 신예라면, JVM 용 스크립트 언어인 Groovy, Jruby, Jython 등은 이미 많은 유저를 확보했습니다. 그 외에도, Lisp의 현대판인 Clojure, CLR과 JVM에서 동시에 동작하는 Fan, Scheme JVM 버전인 SISC 등이 그야말로 자바를 따라잡기 위해 노력하고 있는 상황입니다.

자바는 이런 언어의 라이브러리를 구현하기 위한 시스템 언어 정도로 물러서고 어플리케이션 프로그래밍은 자바가 아닌 좀 더 생산성이 높은 언어로 하는 시대가 올지도 모르겠습니다.


사족: 언급된 내용 중에서 제가 동적 타이핑에서 가장 불편하다고 생각하는 점 중에 하나는 IDE 개발 도구 지원입니다. Eclipse를 비롯한 자바 개발 도구는 대부분 자바 소스를 파싱해서 AST 형태로 만든 후 각종 리팩토링(이름 변경 등)을 매우 쉽게 만들어 줍니다. 반대로 Python이나 Ruby IDE는 어떤 모듈이나 클래스 인스턴스의 메소드 자동 완성하기가 힘듭니다.


Scala 이상한 점

Posted 2008. 4. 22. 19:48
마소 원고 쓰면서 Scala를 가지고 놀다가 재밌는 사례를 발견했습니다.

val은 보통 변하지 않는 값(immutable)을 선언할 때 쓰는 키워드인데, 다음과 같이 선언을 했더니 오류가 발생하지 않고 x 가 1이 되더군요.

scala> val x: Int = x + 1
x: Int = 1


우변의 x + 1은 x가 아직 초기화 되지 않았기 때문에 오류가 발생해야 맞을 것 같은데, 신기하게 그냥 0으로 초기화되고 1을 더해서 x의 값은 1이 되었습니다. scala-user 메일링 리스트에 물어봤더니, Scala 인터프리터에서 위와 같이 선언하면 다음과 같은 클래스를 생성한다고 합니다.


class Foo {
     int x;
     public Foo() {
         x = x + 1;
     }
 }

x가 필드가 되기 때문에 x은 자동으로 0이 할당되고, x + 1은 1이 됩니다. 이건 구현상의 이슈고, Scala에서는 적절히 오류가 발생해야 맞을 것 같은데, 언어 명세에 어떻게 정의해놨는지 모르겠군요.


Scala에서 Parital Application

Posted 2008. 4. 19. 20:34
scala.user 메일링 리스트에 partial application에 대한 질문이 올라왔군요.

def m(a: Int, b: Int, c: Int) = a + b + c


와 같이 함수 m을 정의한 후에 a와 c의 값을 정해주고 b만 인자로 받는 새로운 함수를 만들어내는 문제입니다.

Scala에서 이 문제에 대한 해답은

scala> def m(a: Int, b: Int, c:Int) = a+b+c
m: (Int,Int,Int)Int

scala> val f=m(1, _:Int, 3)
f: (Int) => Int = <function>

scala> f(2)
res0: Int = 6


Scala에서 _ 는 partial evaluation을 하도록 만들어 줍니다.

참고: partial application과 비슷한 용어로 커링(curring)은 (A, B) => C를 A => (B => C)로 만들어 주는 방법을 말합니다. parital application과 커링은 구분해서 사용해야 합니다. LtU의 Currying != Generalized Partial Application?! 을 참조하세요.

Scala

Posted 2008. 4. 19. 17:09
5월 마소에 Scala 프로그래밍 언어를 소개합니다. Scala는 객제+함수언어를 지향하며 자방 가상 머신(JVM) 위에서 돌아가는 언어입니다. 얼마 전에 블로그에서 한 번 소개를 한 적이 있었습니다.

사실 기본적인 문법 및 HelloWorld 스타일의 예제만 소개만 해서는 어떤 언어나 비슷하기 때문에 Scala의 여러 특징 중에 어떤 점을 부각해서 글을 작성할지 고민을 했습니다. 일단 머리 속에 떠오른 몇 가지 아이디어는 다음과 같았습니다.

1) 자바 플랫폼 언어
 * 기존 라이브러리와의 통합
 * 컴포넌트 활용

2) 함수형 언어
 * 함수 언어의 장점
 * 함수 언어와 객체지향 언어와의 통합

3) 병렬 프로그래밍
 * Actor 모델
 * 다양한 병렬 프로그래밍 도구


자세한 내용은 5월 호에^^;

Programming Erlang 리뷰 완료.

Posted 2008. 4. 16. 02:16
얼마 전에 인사이트 출판사의 부탁으로 김석준 님이 번역하신 Programming Erlang 리뷰를 맡았는데 지금 최종 마무리를 하고 있습니다. 원래 월요일에 리뷰를 마치고 택배로 보냈어야 하는데 까멜레오 릴리즈 준비에 치여서 깜빡하고 있었습니다. 퀵으로 보내드려야 할 듯.

저는 병행/분산 프로그래밍, 외부 함수 호출, 파일/소켓 등 IO, 멀티 코어 CPU 프로그래밍 쪽 챕터를 집중으로 리뷰를 했습니다.

Programming Erlang 번역본은 원서를 그대로 살리기 위해 직역투의 번역이 많았는데, 특히 "그", "이것" 등 과도한 대명사 사용이 조금 번역투의 느낌을 풍겼습니다. 하지만 전체적인 내용은 별다른 오역 없이 무난히 번역되어서 얼랭(erlang)에 관심가진 개발자라면 별다른 두려움 없이 번역서를 읽으셔도 괜찮으리라 생각됩니다.

김석준 님이 여러 감수자들의 의견을 종합해서 반영한 후에 조만간 책이 출간될 것으로 예상됩니다. 많이들 읽어주시고, 얼랭 뿐만 아니라 함수 언어에 대해 관심을 가져보시면 어떨까 합니다.

프로그래밍 언어 학회

Posted 2008. 4. 2. 01:28
프로그래밍 언어 관련 학회는 대표적으로 POPL와 PLDI가 있습니다. 둘 다 광범위한 주제를 다루고 있는데 POPL이 이론쪽으로 치우친 반면에 PLDI는 구현도 중시하는 학회입니다.

Principles of Programming Languages (POPL)

Programming Language Design and Implementation (PLDI)


객체지향 언어 학회들은 다음과 같습니다.

Object-Oriented Programming, Systems, Languages, and Applications (OOPSLA)

European Conference on Object-Oriented Programming (ECOOP)


Foundations of Object-Oriented Languages (FOOL)


비고: 이 글은 정보를 계속 갱신하도록 하겠습니다.

통계 및 데이터 분석용 언어 R

Posted 2008. 3. 31. 21:06
리스프(Lisp), SML, 얼랑(Erlang), 헤스켈(Haskell) 등은 각자 특징은 다르지만 범용 함수형 언어라는 공통점이 있습니다. 이와 달리 몇 가지 한정된 영역에만 쓰이는 특수 목적용 함수 언어도 있습니다. 대표적인 예로 통계 및 데이터 분석용 언어이자 환경인 R입니다. 기능이 1:1로 대응되는 것은 아니지만 매트랩(Matlab)이 장악하고 있는 도메인(데이타 분석, 통계, 수학)을 다룰 수 있는 함수형 언어입니다.

R 언어 홈페이지에 있는 An Introduction to R을 보시면 R의 기본적인 특징과 장단점을 파악하실 수 있습니다. IBM dW에도 Statistical programming with R라는 제목으로 R 프로그래밍 언어 소개가 올라와 있습니다. Part 1. Dabbling with a wealth of statistical facilities 제목의 1부는 기본적인 특징과 데이터 타입을 다루고, Functional programming and data exploration라는 제목의 2부에서는 함수형 언어로서의 특징을 이야기하고 있습니다.

R은 데이터 분석용 언어인만큼 기본 데이터 타입으로 벡터(vector)를 지원하고, 각각의 원소에 셈을 할 수 있는 elementwise 연산자를 지원합니다.

> x <- c(10.4, 5.6, 3.1, 6.4, 21.7)
> 1/x

위 코드는 x에 벡터 (10.4, 5.6, 3.1, 6.4, 21.7)를 바인딩하는 예입니다. 1/x는 elementwise 나눗셈으로 각 원소를 1에 대해서 나눈 결과값을 돌려줍니다.

통계에 강한 만큼 통계에 사용되는 mean (평균), sd (표준편차) 등을 기본으로 제공합니다.

> mean(basement)            # Mean fails if we include unavailable data
[1] NA
> mean(basement, na.rm=TRUE)
[1] 18.87542
> sd(basement, na.rm=TRUE)      # Standard deviation must also exclude NA
[1] 2.472855
> cor(basement, livingroom, use="all.obs")   # All observations: no go
Error in cor(basement, livingroom, use = "all.obs") :
        missing observations in cov/cor
> cor(basement, livingroom, use="complete.obs")
[1] 0.9513366
> cor(outside, livingroom, use="complete.obs")
[1] 0.6446673

물론 계산 후에는 멋진 그래픽으로 보여주는 것도 중요하기 때문에 데이터 시각화(data visualization)도 R의 장점 중에 하나입니다. R로 뽑아낸 그래프의 예는 앞서 언급한 dW 글인 Part 1. Dabbling with a wealth of statistical facilities 를 보시면 됩니다.


Scala

Posted 2008. 3. 27. 01:50
2008년은 함수형 언어가 우리 개발자들의 품으로 한 걸음 더 다가오는 해가 아닐까 싶습니다. .NET에서는 이미 OCaml의 .NET 버전인 F#을 내놓고 열심히 홍보를 하고 있고 자바 진영에서도 JVM을 타겟으로 하는 함수형 언어인 Scala가 조금씩 홍보를 시작한 것 같습니다. (개발 자체는 2001년에 EPFL에서 이미 시작되었지만요.) 마침 올해 초에 IBM developerWorks에 The busy Java developer's guide to Scala: Functional programming for the object oriented 라는 튜토리얼 형태의 글이 올라오기도 했습니다.

구글에서는 이미 2006년에 Scala를 만든 Martin Odersky를 초청해서 The Scala Experiment: Better Language Support for Component Systems? (PDF)라는 제목으로 Scala에 대한 강연을 하기도 했습니다. 참고로 Martin Odersky는 자바 진영에서 굉장히 유명한 사람인데 자바의 제네릭스를 추가하기 위한 Pizza, GJ 프로젝트에 참여했고 이 프로젝트는 결국 자바 5의 제네릭스가 되었습니다. 스스로가 함수 언어에 대한 이론을 기반으로 자바에 실용적인 활용 방안을 모색해 온 사람이라 Scala에도 이런 철학이 그대로 녹아들어가 있습니다.

Scala의 기본적인 아이디어는 함수형 언어의 특징을 객체지향 언어인 자바에 잘 집어넣자는 것입니다. 대신 Pizza나 GJ 처럼 자바 언어를 어느 정도 개선하는 스타일이 아니라 아주 새로운 언어를 만들되 타겟만 JVM으로 하는 방식을 취했습니다. Scala의 초기 논문을 보면 언어의 출발은 Java의 복잡한 컴포넌트를 쉽게 조합할 수 있는 도구에 있었습니다. 컴포넌트 재사용의 편의는 고차함수나 Algebraic Data Type 등 함수 언어 아이디어를 OO와 접목하는 걸로 해결하려고 했고요.

코드는 대충 아래와 같이 생겼습니다. 정작 타이핑을 하는 언어임에도 불구하고 타입 추론의 큰 도움으로 마치 동적인 스크립트 언어 같은 느낌을 줍니다. 실제로 같은 일을 하는 자바 코드에 비해 1/2, 1/3 정도로 코드량이 주는 것을 확인하실 수 있습니다.


object Timer
{
def periodicCall(seconds: Int, callback: () => Unit): Unit =
{
while (true)
{
callback()
Thread.sleep(seconds * 1000)
}
}

def main(args: Array[String]): Unit =
{
periodicCall(1, () =>
Console.println("Time flies... oh, you get the idea."))
}
}


개인적으로 JVM을 타겟으로 하는 프로젝트를 할 일이 생기면 과감히 Scala를 써볼 생각도 있습니다. Scala에 대한 구체적인 소개는 다음 기회에 자세히 다뤄보려고 합니다. 미리 궁금하신 분은 Scala 홈페이지를 방문해주세요.


파이썬 바인딩

Posted 2008. 3. 27. 01:04
까멜레오 프로젝트에 대해서 자주 듣는 질문 중에 하나는 왜 파이썬을 사용했냐는 것입니다. Django 같은프레임워크를 이용한 웹프로그래밍도 아니고 퇴근을 일찍하기 위한 잡무 스크립트를 작성하는 것도 아닌 데스크톱 어플리케이션에 파이썬을 메인 언어로 사용했다는 이야기를 들으면 많은 분들이 어리둥절해 하시기 때문입니다.

파이썬을 사용해서 얻는 가장 큰 장점은 C 언어 바인딩이 편리하다는 사실입니다. 파이썬을 메인 언어로 선택한 이유는 수 십 개의 오픈소스 프로젝트를 가져다가 접목하는 글루(glue) 언어로 파이썬이 장점을 가진다고 생각했기 때문입니다. 특히 리눅스 GNOME 진영의 프로젝트는 대부분 파이썬 바인딩을 제공하고 있습니다. GNOME 프로젝트 자체도 코어는 C/C++을 이용하고 UI와 스크립팅 이슈는 대게 파이썬으로 처리하는 경향이 강합니다.

특히 Glib 라이브러리를 사용하는 (정확히는 GObject) 프로젝트들은 codegen을 이용해 C 헤더 파일에서 파이썬 바인딩을 자동으로 생성해 낼 수 있습니다. 물론, 필요에 따라 일부 함수들을 오버라이드해야 하긴 하지만 언어 바인딩을 자동으로 생성할 수 있다는 장점은 파이썬을 선택한 가장 큰 이유였습니다. IBM DW에 보시면 Wrap GObjects in Python이라는 글이 C 코드에서 파이썬 바인딩을 만들어내는 방법을 잘 보여주고 있습니다.

또한 파이썬 표준 라이브러리에 포함되어 있는 ctypes도 굉장히 유용하게 사용됩니다. 특히 C로 이미 작성된 공유 라이브러리(DLL)를 불러 쓸 때 C 코드를 전혀 작성할 필요 없이 외부 함수를 불러 쓸 수 있다는 것은 파이썬의 큰 장점입니다. pyglet 같은 프로젝트는 ctypes만을 이용해 운영체제의 윈도 시스템과 OpenGL 바인딩을 모두 구현해놨습니다.

파이썬은 이 외에도 C와 파이썬을 혼용할 수 있게 해주는 수많은 외부 함수 인터페이스가 존재합니다. 하지만 과학적 계산 등의 코드가 거의 없는 까멜레오 프로젝트에서는 이런 식의 조합은 거의 필요가 없었습니다. 파이썬 코드도 사실상 내부적으로 C 코드를 불러 쓰는 경우가 대부분이었기 때문입니다.

이렇게만 쓰면 파이썬을 사용한 것이 굉장히 좋은 선택이었던 것처럼 보이는데, 파이썬을 본격적으로 사용하면서 겪은 시행 착오와 실수도 엄청 많습니다. 이 부분에 대해서는 다음 기회에 따로 한 번 정리해 보려고 합니다.

« PREV : 1 : 2 : 3 : NEXT »