레슨 12. 필수 - 리더 매크로(Essential Reader Macros)

리더(reader)는 문자를 데이터로 만든다

레슨 11에서 리스프 리더(reader)가 구성문자들을 심볼과 숫자로 모았으며, 매크로 문자들로 리더를 제어하여 리스트, 문자열, quote된 폼, 주석을 처리하는 것을 보았습니다. 이 모든 경우에서와 같이, 리더(reader)는 문자들을 데이터로 바꿉니다 (좀 더 정확히 하자면, 주석은 "데이터가 아닙니다".)

표준 리더 매크로는 내장 데이터 타입을 다룰 수 있다

지금까지, 우리는 리스프의 기본 문법만을 살펴보았습니다. 이는 리더에 의해 구현되며, 리드테이블(readtable)에 의해 제어됩니다. 리더는 리드테이블에 저장되어있는 정보를 따라 문자들을 처리합니다.

사용자는 리더 매크로를 정의할 수 있다

*readtable*변수를 통해 리드테이블(readtable)에 접근할 수 있으며, 리드테이블에 있는 항목을 조작할 수 있는 함수들을 리스프는 제공합니다. 여러분은 이를 이용하여 리스프 리더의 행동을 바꿀 수 있습니다. 다음 예제에선, 문법을 바꾸어 []를 이용하여 평가되지 않는 리스트를 작성하였습니다:

;;이는 틀렸습니다:
(1 2 3 4 5 6)
;;>| Error: 1 is not a function

;; 대신에 이렇게 해야 합니다:
'(1 2 3 4 5 6)
;;=> (1 2 3 4 5 6)

;;새로운 문법을 정의하여
;; '(1 2 3 4 5 6)   ; 대신에
;;  [1 2 3 4 5 6]   ; 이처럼 작성할 수 있게 합시다.
(defun open-bracket-macro-character (stream char)
  `',(read-delimited-list #\] stream t))
;;=> OPEN-BRACKET-MACRO-CHARACTER

(set-macro-character #\[ #'open-bracket-macro-character)
;;=> T

(set-macro-character #\] (get-macro-character #\)))
;;=> T

;;이제 테스트 해봅시다:
[1 2 3 4 5 6]
;;=> (1 2 3 4 5 6)

처음 저희는 (1 2 3 4 5 6)을 평가해보려 시도했습니다: 1은 함수가 아니기에, 이는 옳지 않습니다. 이제 저희가 해야만하는 것은 리스트를 quote 하는 것입니다. 그러나 이러한 작업을 매번 해야한다면, 더욱 편리한 문법을 원하게 될 것입니다. 좀 더 구체적으로, [...]'(...) 처럼 동작했으면 좋겠습니다.

이를 수행하기 위해, 인수를 평가하지 않는 특수 리스트 리더 매크로 함수를 정의해야 합니다. 리더가 [ 문자를 만나면 함수가 호출되도록 할 것입니다; 함수는 ] 문자를 만나면 리스트를 반환할 것입니다. 모든 리더 매크로 함수는 두 인수에 의해 호출됩니다: 입력 스트림과 매크로를 작동시키는 문자.

리스프에는 리스트를 읽을 수 있도록 설계된 함수가 있어, 쉽게 리드 매크로를 만들 수 있었습니다. READ-DELIMITED-LIST는 하나의 인수를 기다립니다 - 현재 읽고 있는 리스트를 종료시키는 문자. 다른 두개의 인자는 선택 사항입니다 - 입력 스트림과 플래그 (리더 매크로 함수에서 사용될땐 보통 T로 설정되는). READ-DELIMITED-LIST는 종료 문자를 마주치기 전까지 입력 스트림에서 오브젝트를 읽은 후, 모든 오브젝트를 리스트로 반환합니다. 이것만으로도 평가를 억제하는 것(suppressing)을 제외한 저희가 필요한 모든것을 수행 할 수 있습니다.

레슨 3에서 봤던 것 처럼, QUOTE (혹은 ')는 평가를 막습니다. 그러나 여기서 '(READ-DELIMITED-LIST ...)를 사용할 수 없습니다; 이는, 저희가 평가하고자 하는 폼의 평가도 막아버립니다... 대신, quote된 폼에 대해 선택적으로 평가를 할 수 있는 `(레슨 8 참조)를 사용하였습니다.

저희 OPEN-BRACKET-MACRO-CHARACTER의 정의에서 내부의 폼을 평가하지만 결과는 quote된 결과를 반환하기 위해

`',form

을 사용하였습니다.

  • 리스프는 프로그래머를 위해 6개의 문자를 예약하였습니다: [ ] { } ! ?

여러분은 이중 일부나 전체를 매크로 문자를 정의할 수 있습니다. 그러나, 다른 프로그래머와 코드를 공유할때, 논란이 될 수 있다라는 점을 주의하셔야 합니다.

짚고 넘어가기

  • *readtable*