LambdaCalculus 소개

Functional programming을 잘 아는 것도 아니고, Lambda calculus를 제대로 배운 적도 없으면서 팀에다가 소개하는 시간을 가졌다.


Posted in 기타 | Tagged , , , | Leave a comment

Go와 Node.js

Go언어와 더불어 요즘 관심을 가지고 있는 언어가 Node.js입니다.
(언어라고 하기는 조금 그런가요?)

두 언어가 양 극단이라고 볼 수도 있지만, 어떤 측면으로는 굉장히 닮아 있는 것 같습니다. Node.js는 그만큼 Low-level을 다루고 있고, Go는 또 Dynamic한 특정이 강하다.. 라는 의미이기도 하겠죠?

제가 두 언어를 모두 잘 알아서는 이렇다라고 딱 부러지게 말할 입장은 아니고요. 두 언어의 튜토리얼에 나와 있는 http서버 예제를 따라가다가 느낀 것입니다.

다음은 Node.js의 전형적인 Hello World 예제 입니다.

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337);
console.log('Server running at http://127.0.0.1:1337/');

Go의 Hello World를 볼까요?

package main
import (
  "fmt"
  "net/http"
)
func main() {
  http.ListenAndServe(":1337", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request){
    w.Write([]byte("Hello World\n"))
  }))
  fmt.Println("Server running at http://127.0.0.1:1337/")
}

거의 흡사하지 않나요? (좀더 비슷하게 보이도록 하려고 조금 수정한 것도 있습니다) 타입 선언을 제외하면 사실상 같다고 할수 있죠.

내부적으로는 goroutine을 사용하는 Go와 single thread 만으로 동작하는 Node.js가 서로 다르지만, API를 설계하는 측면에서는 흡사한 부분이 분명히 있고, 그것은 두 언어의 중요한 설계 철학이라고 생각합니다.

객체지향적 설계를 벗어나서, “꼭 필요한 타입/함수만을 import로 가져오고, 기능 확장은 콜백 혹은 콜백의 묶음(인터페이스)를 이용한다”라는 것이죠. Java Servlet과 비교해보면 차이가 두드러집니다. 상속/재정의를 통해 기능확장을 하는 것과 차이나는 것이죠.

두 언어의 다른 라이브러리들은 어떤지, 그리고 두 언어가 앞으로 발전해 나가는 모습은 어떠할지 지켜볼 필요가 있을 것 같습니다. 서로 도움을 주고 받을 부분이 분명 있을 것 같네요.

Posted in 기타 | Tagged , | Leave a comment

LISP 구현하기 – MACRO

진행 중인 Go로 LISP 구현하기 개인 프로젝트(링크)에, “MACRO Definitions for LISP”을 참고하여 MACRO를 구현했다.

이 문서에는 LISP 1.5를 기준으로 MACRO를 도입한 새로운 interpreter를 M-expression으로 상세히 기술되어 있다. 다만 LISP 1.5의 시스템 정의를 조금 알아야 문서를 읽을 수 있어서, “LISP 1.5 Programmer’s Manual”도 같이 봐야 했다.

MACRO definitions for LISP

LISP 1.5에는 Symbol마다 Property list라는 것이 있다. Property list에는 indicator와 value의 쌍이 이어진다. indicator중에서 EXPR이라는 것이 사용자 정의 함수이다. DEFINE 함수로 정의할 수 있다.

DEFINE ( (
(FOO) (LAMBDA (X) ...)
))

동일한 문법을 사용하되, MACRO 함수를 이용하면 MACRO라는 indicator로 해당 함수 정의를 저장해 놓는다. DEFINE 함수와 형태가 일치하므로 내부적으로는 deflist[l;ind]를 이용하여 구현된다. (l은 정의 리스트, ind는 indicator) 즉, define[l] => deflist[l;EXPR]. macro[l] => deflist[l;MACRO]이다.

MACRO ( (
(M1) (LAMBDA (FORM) ...)
))

사용자로부터 식을 읽어들일때마다 매크로를 적용하여 form을 확장(expand)하는 것으로 구현할 수 있다.

구현하기

LISP 1.5는 기본적으로 입력 내용을 함수와 인자리스트형태로 받아서 evalquote[f;a]로 넘긴다. 그래서 Scheme과는 다른 위와 같은 모양이 나오는 것이다. Micro Manual For LISP을 보면, (defun …)형태로 사용자 함수를 정의하는 방식이 소개되므로, 이 방식을 매크로 정의에 사용하면 (defmacro …)형태로 매크로를 정의하도록 할 수 있다.

(defmacro select (form)
  ( (lambda (symbol) (list (list 'lambda (list symbol)
    (cons 'cond
      (maplist (cddr form)
        (function (lambda (l) (cond
            ( (null (cdr l))
              (list 'T (car l)))
            (T
              (list (list 'equal symbol (caar l)) (cadar l))))))))) (cadr form)))
   (gensym)))

문서의 끝에 나온 select 구현을 충실히 옮기면 위와 같다. 아직 quasiquote, unquote 등이 도입되기 전이라 읽기가 상당히 어렵다. 그 필요성을 바로 알 수 있다.

LISP 1.5에는 Symbol마다 Property List가 있지만, symbol->value 사전 형태의 구현에서는 EXPR 사전과 MACRO 사전을 따로 관리해야 하는 문제가 있다. 우선은 indicator에 해당하는 내용을 Symbol에 덧붙여서 저장하고 불러오는 방법으로 같은 효과를 얻을 수 있다.

Posted in 기타 | Tagged | Leave a comment