본문 바로가기

Architecture for Software/Lisp

[2] 리스프의 근원(The Roots of Lisp): 7개의 원시 연산자

해커와 화가(Hackers & Painters)라는 책으로 유명한 폴 그레이엄(Paul Graham)의 사이트에 있는 리스프의 근원(The Roots of Lisp)이란 글을 공부겸 번역하고 있습니다.

2번째 글인 7개의 원시 연산자(Seven Primitive Operators)란 글을 올립니다. 원문은 리스프의 근원(The Roots of Lisp) 에 있는 "Complete Article (Postscript)pad"를 참고하시기 바랍니다.

리스프(Lisp)에 관심있는 분들에게 많은 도움이 되었으면 좋겠습니다.



1. 7개의 원시 연산자(Seven Primitive Operators)

시작하려면, 우리는 표현식(expression)을 알아야 한다. 표현식은 foo와 같은 문자열(sequence of letters)이거나, 0개 이상의 표현식을 포함한 리스트(list)와 같은 원자(atom)로 구성되어 있으며, 공백문자(white space)와 닫혀진 괄호(parenthese)로 구분되어진다.
여기에 몇가지 표현식이 있다.

foo
()
(foo)
(foo bar)
(a b (c) d)

마지막 표현식은 4개의 요소로 구성된 리스트이며, 3번째 요소는 그 자신이 리스트의 첫번째 요소이다.

산술적으로 1 + 1이란 표현식의 값은 2이다. 유효한 리스프(Lisp) 표현식들 역시 값들을 가진다. 만약 e 라는 표현식이 v라는 값을 산출하였다면, 우리는 이를 e가 v를 반환(e returns v)하였다고 말한다.  우리는 다음 단계에서 여러 종류의 표현식이 어떠한 종류의 반환을 할 수 있은지 정의하고자 한다.

만약 표현식이 리스트이면, 우리는 첫번째 요소를 연산자(operator)라고 부르고 나머지 요소들은 인자(argument)들 이라고 부른다. 우리는 7개의 원시(7개의 公理 내에 있는) 연산자들을 정의할 것이다. 이는 quote, atom, eq, car, cdr, conscond이다.


1. (quote x)는 x를 반환한다. 가독성을 위해서 우리는 (quote x)'x와 같이 단축시킬 수 있다. (참고로 quote의 뜻은 인용한다는 의미입니다. 따라서 인용하여 단축시킬 수 있다는 의미입니다.)

> (quote a)
a
> 'a
> (quote (a b c))
(a b c)

필자가 LispWorks 5.1 Personal Edition에서 실행한 결과는 위와 같습니다.




2. (atom x)는 만약 x 값이 원자이거나 비어있는 리스트라면 원자 t를 반환한다. 다른말로 이는 ()를 리턴한다. 리스프에서는 관례적으로 원자 t참(truth)을 표기하거나, 비어있는 리스트의 거짓(falsity)을 표기할때 사용한다.

> (atom 'a)
t
> (atom '(a b c))
()
> (atom '())
t

필자가 LispWorks 5.1 Personal Edition에서 실행한 결과는 위와 같습니다.


지금 우리는 quote의 예를 보면서 누군가의 인자(argument) 값을 구하는 연산자를 확인하였다. 리스트에서 인용함으로써 우리는 이것이 값을 구하는(evaluation)것을 막을 수 있다. atom과 같은 연산자로 인자와 같이 주어진 인용되지 않은 리스트는 다음 코드와 같이 수정되어야 한다.

> (atom (atom 'a))
t

인용되었던 리스트는 단순한 리스트와 같이 수정되어졌으며, 이 경우는 두개의 요소를 가지는 리스트에 대한 경우이다.

> (atom '(atom 'a))
()

필자가 LispWorks 5.1 Personal Edition에서 실행한 결과는 위와 같습니다.



이 결과는 우리가 영어에서 인용을 사용하는 방법이다. 캠브리지(Cambridge)는 메사추세츠(Massachusetts)에 있는 마을인데 9만명의 사람들을 포함하고 있다. "Cambridge"라는 단어는 9 문자를 포함하고 있다.

인용은 외국어의 개념중 일부인것 같은데, 왜냐하면 몇몇 다른 언어들은 이와 같은 것들을 가지고 있기 때문이다.
인용은 리스프의 가장 독특한 특징들중에 하나인데, 리스프의 가장 큰 특징은 코드(code)와 자료(data)는 같은 자료 구조(data structure)에서 구성하는 것이며, quote 연산자를 통하여 자료 구조 내에서 구별할 수 있는 방안을 제공해 주어, 리스프의 독특한 자료구조를 quote 연산자로 묶을 수 있다.


3. (eq x y) 는 만약 x의 값과 y의 값이 같은 원자(atom)이거나, 둘다 비어있는 리스트이거나, 그외에 ()인 경우 t를 반환한다.

> (eq 'a 'a)
t
> (eq 'a 'b)
()
> (eq '() '())
t

필자가 LispWorks 5.1 Personal Edition에서 실행한 결과는 위와 같습니다.




4. (car x)x의 값이 리스트로 되어 있을 것이라고 예상하여, 첫번째 요소를 반환한다.

> (car '(a b c))
a


5. (cdr x)x의 값이 리스트로 되어 있을 것이라고 예상하여, 첫번째 요소 뒤에 있는 모든 남은 요소들을 반환한다.

> (cdr '(a b c))
(b c)


6. (cons x y)y의 값이 리스트로 되어 있을 것이라고 예상하며, y 값의 요소들에 x 값을 포함한 리스트를 반환한다. 

> (cons 'a '(b c))
(a b c )
> (cons 'a (cons 'b (cons 'c '())))
(a b c)
> (car (cons 'a '(b c)))
a
> (cdr (cons 'a '(b c)))
(b c)


7. (cond (p1 e1) ... (pn en)) 는 다음 것들의 값을 구한다. p 표현식은 하나의 반환값이 t일때까지 순서대로 값을 구한다. t인것이 발견되면, 대응되는 e 표현식에 모든 cond 표현식의 값인것처럼 값을 반환한다.

> (cond ((eq 'a 'b) 'first)
             ((atom 'a) 'second))
'second

필자가 LispWorks 5.1 Personal Edition에서 실행한 결과는 위와 같습니다.




우리의 7개의 원시 연산자 중 5개는, 인자들이 항상 연산자로 시작되는 표현식을 가지고 실행되어 값이 구해진다. 이러한 형태의 연산자를 우리는 function 형이라고 부를 것이다.



후후~ 제법 쉽지 않은 번역이었습니다. 아~ 군데 군데 빈틈이 보입니다. 의역을 덧붙였지만, 설명을 많이 첨가해야 될 듯합니다.

그래도 참 간결하면서 핵심만 잘 설명해주는 글이라 공부하는게 즐겁습니다.
원자를 정의하고, 인용하고, 이를 바탕으로 리스트의 요소들을 확인하고 열거한다면, 정말 리스트 하나로 모든 프로그래밍이 끝날듯 합니다.

그간 이런 프로그래밍의 묘미를 왜 몰랐을까요~ :-)

제 글을 보시는 분들중에 프로그래밍에 많은 관심을 가지고 계시는 분들이라면 가급적 빨리 리스프(Lisp)를 접해보시길 권해드리고 싶습니다. 혼자 보시기 어려우시면 Lisp을 좋아하는 사람들의 그룹(한국 리스퍼) 에서 함께하시면 더욱 좋을것 같습니다.

감사합니다. ;-)