Macro & compilation
Ikhoon
Introduction
 Macro
 호칭
 Macro function or 줄여서 macro
 용도
 Lisp의 syntax를 확장하는 하나의 방법
 Tool
 PPMX(pretty print macro expansion)
 Compiler
 역할
 Lisp프로그램을 기계언어로 바꾸는 역할
 효과
 일반적으로 10 ~ 100배 정도의 성능 향상
Macro as shorthand
 (INCF A) vs. (SETQ A (+ A 1))
 매크로는 복잡한 표현을 간략하게 할 수 있음
 SETF vs. SETQ
 매크로 SETF, INCF는 special 함수 SETQ보다 smart함
 (incf (aref (nth array-num *list-of-arrays*)
(first subscripts)))
 DEFSTRUCT 매크로
 MAKE-STARSHIP, STARSHIP-P, STARSHIP-NAME 의 함
수를 암묵적으로 생성
Macro expansion
 Lisp의 Macro는 자동으로 표현식을 확장
 입력 인자를 평가하지 않는 약어 확장 함수
 > (ppmx (incf a))
Macro expansion:
(SETQ A (+ A 1))
 > (ppmx (incf a))
Macro expansion:
(LET ((#:G0144 (+ A 1)))
(SETQ A #:G0144))
Defining a macro
 DEFMACRO
 매크로는 defmacro를 이용해서 정의
 Syntax는 defun과 유사
 Macro 함수는 평가되어 질 수 있는 표현식을 만들어 반환
 간단한 버전의 incf
 list를 이용해서 lisp이 평가할수있는 표현식 생성
 (defmacro simple-incf (var)
(list ’setq var (list ’+ var 1)))
(setf a 4)
> (simple-incf a)
5
 (defmacro simple-incf (var &optional (amount 1))
(list ’setq var (list ’+ var amount)))
(setf b 2)
> (simple-incf b (* 3 a))
17
Why macro?
 Function or MACRO
 INCF 함수는 매크로로만 만들 수 있다.
 함수버전 incf
(defun faulty-incf (var)
(setq var (+ var 1)))
(setf a 7)
> (faulty-incf a)
8
> (faulty-incf a)
8
> a
7 ;; a 값이 증가 되지 않음
 인자 값이 함수로 들어가기 전에 평가되어짐
 증가한 값은 함수내의 지역 변수 var이지 a가 아님
Macros as syntactic extensions
 Macro의 목적
 Lisp Language의 syntax확장
 Macro vs. Function
1. Function의 인자는 항상 평가 된다. Macro의 인자는 평가
되지 않는다.
2. Function의 결과값은 어떤 것이든지 될 수 있다. Macro의
반환 값은 반드시 유효한 Lisp 표현이어야 한다.
3. Macro가 반환한 표현은 즉시 평가되어 진다. Function의
반환 결과는 평가되어 지지 않는다.
Macros as syntactic extensions
 Special functions
 SETQ, IF, LET, BLOCK 등..
 Common lisp의 가장 하위 레벨의 블록들
 Scoping, block 과 loop과 같은 기본적인 제어구조를 책임
짐
 Macro와 마찬가지로 인자들을 평가하지 않음
 평가하기 위한 표현을 반환하자 않음
 새로운 special function을 쓸 수 없음, lisp implementer만
이 할 수 있음
The backquote character
 Backquote [ ` ]
 Quote와 유사하게 list를 인용하기 위해서 사용
 Unquote
 Comma [ , ]
 Backquote된 list의 어떤 값 앞에 comma가 붙게 되면 unquote됨
 Unquote는 쓰여진 표현이 자체가 아니가 그것의 값을 의미
(setf name ’fred)
> `(this is ,name from pittsburgh)
(THIS IS FRED FROM PITTSBURGH)
> `(i gave ,name about ,(* 25 8) dollars)
(I GAVE FRED ABOUT 200 DOLLARS)
 Simple-incf
 (defmacro simple-incf (var) ;; list를 사용한 매크로
(list ’setq var (list ’+ var 1)))
 (defmacro simple-incf (var &optional (amount 1)) ;; backquote를 사용한 매크로
`(setq ,var (+ ,var ,amount)))
Splicing with backquote
 Splice
 Comma-at [ ,@ ]
 ,@에 의해서 생기는 결과 값은 단순히 삽입되는 것이 아니라 접
합되어(spliced)짐
 ,@는 가장 외각의 괄호가 없어 지는 역할을 하기 때문에 반드시
list에서만 적용해야 함
(setf name ’fred)
(setf address ’(16 maple drive))
> `(,name lives at ,address now) ;;
Inserting.
(FRED LIVES AT (16 MAPLE DRIVE) NOW)
> `(,name lives at ,@address now) ;;
Splicing.
(FRED LIVES AT 16 MAPLE DRIVE NOW)
The compiler
 Function compilation
 COMPILE 이라는 명령어를 통해서 가능
 File compilation
 COMPILE-FILE 이라는 명령어를 통해서 할 수 있음
 성능
 10 ~ 100배정도 향상 가능
Compiling entire programs
 에러메시지 처리
 Global variable
 Global variable을 사용하면 “assumed to be SPECIAL” 이라는 경고
문구가 출력됨
 DEFVAR, DEFPARAMETER, DEFCONSTANT를 적절하게 이용하
여 경고 메시지를 없앨 수 있음
 선언은 파일의 초반부 OR 그 값을 참조하는 함수 전에 선언되어야
함
 MACRO
 매크로의 선언은 반드시 어떤 함수가 그것을 참조하기 전에 놓여져
야 함
 함수 foo 가 매크로 bar를 부를 때 bar가 foo보다 뒤에 있다면 foo를
컴파일 할 때 매크로 bar를 확장해야 하는 것을 알지 못함
 Built-in 함수
 내장함수 재정의 하면 컴파일 에러가 남
Advanced topics:
The &body lambda-list keyword
 WHILE loop in lisp
 (defmacro while (test &body body)
`(do ()
((not ,test))
,@body))
 매크로를 통해서 새로운 syntax를 추가함
 &body
 &body는 &rest와 동일한 기능
 남겨진 인자들이 list의 형태로 넘어옴
 매크로를 읽을 때 나머지 부분들이 Lisp code의 body부분
이 된다는 것을 알려줌
Advanced topics:
Destructuring lambda lists (1)
 Destructuring
 매크로는 입력인자를 평가 안 함
 입력 표현을 자동으로 분리될 수 있도록 List 처럼 취급 가능
 매크로에서 가능
 복잡한 syntax 제어 구조에 용이
 (defmacro mix-and-match (p q) ;; not destruturing
(let ((x1 (first p))
(y1 (second p))
(x2 (first q))
(y2 (second q)))
`(list ’(,x1 ,y1)
’(,x1 ,y2)
’(,x2 ,y1)
’(,x2 ,y2))))
 (defmacro mix-and-match ((x1 y1) (x2 y2)) ;; destruturing
`(list ’(,x1 ,y1)
’(,x1 ,y2)
’(,x2 ,y1)
’(,x2 ,y2)))
Advanced topics:
Destructuring lambda lists - example
 DOVECTOR
 (defmacro dovector ((var vector-exp
&optional result-form)
&body body)
`(do* ((vec-dov ,vector-exp)
(len-dov (length vec-dov))
(i-dov 0 (+ i-dov 1))
(,var nil))
((equal i-dov len-dov) ,result-form)
(setf ,var (aref vec-dov i-dov))
,@body))
> (dovector (x ’#(foo bar baz))
(format t "~&X is ~S" x))
X is FOO
X is BAR
X is BAZ
NIL
 vec-dov, len-dov, i-dov 는 초기값을 담기 위한 지역 변수
 변수 이름 충돌을 막기 위해서 package system과 gensyms를 사용하는 것이 바람직하지만
이 책의 범위를 벗어 나는 내용
?
Advanced topics:
Macros and lexical scoping
 함수로 incf 만들기
 값이 평가되는 것이 피하기 위해 symbol을 사용함
 변수에 대한 Read & Update가 가능해야 함
 전역변수는 가능
 (defun faulty-incf (var)
(set var (+ (symbol-value var) 1)))
(setf a 7)
> (faulty-incf ’a)
8
> (faulty-incf ’a)
9
> a
9
 지역 변수는 매크로만 가능
 (defun test-simple (turnip)
(simple-incf turnip))
(defun test-faulty (turnip)
(faulty-incf ’turnip))
> (test-simple 37)
38
> (test-faulty 37)
 Error: TURNIP unassigned variable.
 FAULTY-INCF의 부모 lexical-context는 global-context이기 때문에 TEST-FAULTY의 지역변수 TURNIP에 lexically하
게 접근이 되어지지 않는다.
Advanced topics:
Dynamic scoping
 Lexical scoping
 정의
 X변수에 접근하기 위해서는 X가 정해진 body 안에서만 접근가능
 전역함수
 DEFUN으로 정의 되어짐
 자신의 local 변수와 전역 변수 접근 가능
 지역함수
 함수 BAR안에 lambda 표현 식으로 정의
 자신의 변수, BAR의 변수와 전역 변수 접근 가능
 Dynamic scoping
 Dynamic variable은 Special variable이라고도 부름
 정의
 변수 X가 special로 선언되면 다른 함수의 지역 변수가 될 수 없고
어디서나 접근이 가능
 DEFVAR 매크로를 통해 정의될 수 있음
Advanced topics:
Dynamic scoping - example
 (defvar birds) ;; bird를 special로 선언
(setf fish ’(salmon tuna)) ;; fish – lexical
(setf birds ’(eagle vulture)) ;; birds – special
(defun ref-fish () ;; 참조 함수 선언
fish)
(defun ref-birds ()
birds)
(ref-fish) => (salmon tuna) ;; top level에서 실행
(ref-birds) => (eagle vulture)
 (defun test-lexical (fish)
(list fish (ref-fish)))
> (test-lexical ’(guppy minnow)) ;; lexical 변수 참조
((GUPPY MINNOW) (SALMON TUNA)) ;; ref-fish함수 안의 fish는 lexical scoping에 따라 전역 변수 참조
 (defun test-dynamic (birds)
(list birds (ref-birds))) ;; dynamic 변수 참조
> (test-dynamic ’(robin sparrow)) ;; ref-birds 함수 안의 birds는 dynamic 변수 bird 참조
((ROBIN SPARROW) (ROBIN SPARROW))
 > (ref-birds)
(EAGLE VULTURE)
 TEST-DYNAMIC의 body로 들어 갈 때 새로운 dynamic 변수 birds가 새기고 TEST-DYNAMIC을 떠날 때 까지 변수
birds는 이값을 참조 하게 됨
Advanced topics:
defvar, defparameter, defconstant
 DEFVAR
 초기 값 없이 선언 될 수 있음
 (defvar *total-glasses*)
 한번 그 값이 선언되면 defvar를 통해서 바꿀 수 없음
> (defvar *total-glasses* 0
"Total glasses sold so far")
> (defvar *total-glasses* 3
"Total glasses sold so far")
> *total-glasses*
0
 DEFPARAMETER
 초기 값과 함께 선언 되어야 함
 (defparameter abc 10)
 선언된 값을 defparameter를 통해 바꿀 수 있음
> (defparameter *max-glasses* 500
"Maximum number of glasses we can make")
> (defparameter *max-glasses* 300)
> *max-glasses*
300
 defvar와 defparameter는 똑같은 문법 구조이지만 defparameter는 프로그램이 실행되는 동안 변화되지 않아야 하는 값에 사용
 DEFCONSTANT
 만들어진 상수는 절대 바뀌지 않음
 Lisp의 special valiable들은 관습적으로 *로 둘러 싸서 표현 하지만 defconstant는 예외를 적용
 Lisp는 PI와 같은 내장 상수들이 있음
Advanced topics:
Rebinding special variables
 Function 인자
 함수의 인자를 special 변수의 이름으로 지정하여 호출 시 rebinding
(defun print-in-base (*print-base* x)
(format t "~&~D is written ~S in base ~D."
x x *print-base*))
> (print-in-base 2 205)
205 is written 11001101 in base 2.
NIL
 LET
 LET을 통한 바인딩
(defvar *foo* 2)
(defun bump-foo ()
(incf *foo*))
(defun rebind-boo ()
(let ((*foo* 100))
(incf *foo*)
(bump-foo)))
Ansi Lisp:
Macro design – example(1)
 ntimes 매크로 만들기
 입력된 숫자횟수만큼 반복 실행하는 매크로
 (ntimes count &body body)
 > (ntimes 10
(princ "."))
..........
NIL
 References
 ansi lisp
 http://onlisp.blogspot.com/2007/12/10-ansi-common-lisp.html
Ansi Lisp:
Macro design – example(2)
 ntimes 매크로
 (defmacro ntimes (n &rest body)
`(do ((x 0 (+ x 1)))
((>= x ,n))
,@body))
 문제점
 변수 x를 생성해서 기존에 변수 x가 있었다면 의도치 않은 결과 발생
 잘못된 예
 (let ((x 10))
(ntimes 5
(setf x (+ x 1)))
x)
10
 X에 10을 할당하고 그 값을 5번 증가 시켜야 하지만 결과 값은 그대로 10이 됨
 매크로 확장
 (let ((x 10))
(do ((x 0 (+ x 1)))
((>= x 5))
(setf x (+ x 1))) ;; let으로 생성된 x가 아닌 do안의 변수 x가 증가
x)
Ansi Lisp:
Macro design – example(3)
 수정된 ntimes 매크로
 do loop안의 변수를 gensym을 통하여 프로그램내의 어느 심볼과도 같지 않게 만듬
 (defmacro ntimes (n &rest body)
(let ((g (gensym)))
`(do ((,g 0 (+ ,g 1)))
((>= ,g ,n))
,@body)))
 문제점
 반복 평가
 do 문의 body가 평가 될때 마다 n이 새롭게 평가 된다.
 잘못된 예
 > (let ((v 10))
(ntimes (setf v (- v 1))
(princ ".")))
.....
NIL
 원하는 결과는 v에서 10에서 1을 뺀 9개의 점을 출력
 매크로 확장
 (let ((v 10))
(do ((#:g1 0 (+ #:g1 1)))
((>= #:g1 (setf v (- v 1))))
(princ ".")))
Ansi Lisp:
Macro design – example(4)
 수정된 ntimes 매크로
 (defmacro ntimes (n &rest body)
(let ((g (gensym))
(h (gensym)))
`(let ((,h ,n))
(do ((,g 0 (+ ,g 1)))
((>= ,g ,h))
,@body))))
 문제점
 해결됨
 끝

Macro & compilation

  • 1.
  • 2.
    Introduction  Macro  호칭 Macro function or 줄여서 macro  용도  Lisp의 syntax를 확장하는 하나의 방법  Tool  PPMX(pretty print macro expansion)  Compiler  역할  Lisp프로그램을 기계언어로 바꾸는 역할  효과  일반적으로 10 ~ 100배 정도의 성능 향상
  • 3.
    Macro as shorthand (INCF A) vs. (SETQ A (+ A 1))  매크로는 복잡한 표현을 간략하게 할 수 있음  SETF vs. SETQ  매크로 SETF, INCF는 special 함수 SETQ보다 smart함  (incf (aref (nth array-num *list-of-arrays*) (first subscripts)))  DEFSTRUCT 매크로  MAKE-STARSHIP, STARSHIP-P, STARSHIP-NAME 의 함 수를 암묵적으로 생성
  • 4.
    Macro expansion  Lisp의Macro는 자동으로 표현식을 확장  입력 인자를 평가하지 않는 약어 확장 함수  > (ppmx (incf a)) Macro expansion: (SETQ A (+ A 1))  > (ppmx (incf a)) Macro expansion: (LET ((#:G0144 (+ A 1))) (SETQ A #:G0144))
  • 5.
    Defining a macro DEFMACRO  매크로는 defmacro를 이용해서 정의  Syntax는 defun과 유사  Macro 함수는 평가되어 질 수 있는 표현식을 만들어 반환  간단한 버전의 incf  list를 이용해서 lisp이 평가할수있는 표현식 생성  (defmacro simple-incf (var) (list ’setq var (list ’+ var 1))) (setf a 4) > (simple-incf a) 5  (defmacro simple-incf (var &optional (amount 1)) (list ’setq var (list ’+ var amount))) (setf b 2) > (simple-incf b (* 3 a)) 17
  • 6.
    Why macro?  Functionor MACRO  INCF 함수는 매크로로만 만들 수 있다.  함수버전 incf (defun faulty-incf (var) (setq var (+ var 1))) (setf a 7) > (faulty-incf a) 8 > (faulty-incf a) 8 > a 7 ;; a 값이 증가 되지 않음  인자 값이 함수로 들어가기 전에 평가되어짐  증가한 값은 함수내의 지역 변수 var이지 a가 아님
  • 7.
    Macros as syntacticextensions  Macro의 목적  Lisp Language의 syntax확장  Macro vs. Function 1. Function의 인자는 항상 평가 된다. Macro의 인자는 평가 되지 않는다. 2. Function의 결과값은 어떤 것이든지 될 수 있다. Macro의 반환 값은 반드시 유효한 Lisp 표현이어야 한다. 3. Macro가 반환한 표현은 즉시 평가되어 진다. Function의 반환 결과는 평가되어 지지 않는다.
  • 8.
    Macros as syntacticextensions  Special functions  SETQ, IF, LET, BLOCK 등..  Common lisp의 가장 하위 레벨의 블록들  Scoping, block 과 loop과 같은 기본적인 제어구조를 책임 짐  Macro와 마찬가지로 인자들을 평가하지 않음  평가하기 위한 표현을 반환하자 않음  새로운 special function을 쓸 수 없음, lisp implementer만 이 할 수 있음
  • 9.
    The backquote character Backquote [ ` ]  Quote와 유사하게 list를 인용하기 위해서 사용  Unquote  Comma [ , ]  Backquote된 list의 어떤 값 앞에 comma가 붙게 되면 unquote됨  Unquote는 쓰여진 표현이 자체가 아니가 그것의 값을 의미 (setf name ’fred) > `(this is ,name from pittsburgh) (THIS IS FRED FROM PITTSBURGH) > `(i gave ,name about ,(* 25 8) dollars) (I GAVE FRED ABOUT 200 DOLLARS)  Simple-incf  (defmacro simple-incf (var) ;; list를 사용한 매크로 (list ’setq var (list ’+ var 1)))  (defmacro simple-incf (var &optional (amount 1)) ;; backquote를 사용한 매크로 `(setq ,var (+ ,var ,amount)))
  • 10.
    Splicing with backquote Splice  Comma-at [ ,@ ]  ,@에 의해서 생기는 결과 값은 단순히 삽입되는 것이 아니라 접 합되어(spliced)짐  ,@는 가장 외각의 괄호가 없어 지는 역할을 하기 때문에 반드시 list에서만 적용해야 함 (setf name ’fred) (setf address ’(16 maple drive)) > `(,name lives at ,address now) ;; Inserting. (FRED LIVES AT (16 MAPLE DRIVE) NOW) > `(,name lives at ,@address now) ;; Splicing. (FRED LIVES AT 16 MAPLE DRIVE NOW)
  • 11.
    The compiler  Functioncompilation  COMPILE 이라는 명령어를 통해서 가능  File compilation  COMPILE-FILE 이라는 명령어를 통해서 할 수 있음  성능  10 ~ 100배정도 향상 가능
  • 12.
    Compiling entire programs 에러메시지 처리  Global variable  Global variable을 사용하면 “assumed to be SPECIAL” 이라는 경고 문구가 출력됨  DEFVAR, DEFPARAMETER, DEFCONSTANT를 적절하게 이용하 여 경고 메시지를 없앨 수 있음  선언은 파일의 초반부 OR 그 값을 참조하는 함수 전에 선언되어야 함  MACRO  매크로의 선언은 반드시 어떤 함수가 그것을 참조하기 전에 놓여져 야 함  함수 foo 가 매크로 bar를 부를 때 bar가 foo보다 뒤에 있다면 foo를 컴파일 할 때 매크로 bar를 확장해야 하는 것을 알지 못함  Built-in 함수  내장함수 재정의 하면 컴파일 에러가 남
  • 13.
    Advanced topics: The &bodylambda-list keyword  WHILE loop in lisp  (defmacro while (test &body body) `(do () ((not ,test)) ,@body))  매크로를 통해서 새로운 syntax를 추가함  &body  &body는 &rest와 동일한 기능  남겨진 인자들이 list의 형태로 넘어옴  매크로를 읽을 때 나머지 부분들이 Lisp code의 body부분 이 된다는 것을 알려줌
  • 14.
    Advanced topics: Destructuring lambdalists (1)  Destructuring  매크로는 입력인자를 평가 안 함  입력 표현을 자동으로 분리될 수 있도록 List 처럼 취급 가능  매크로에서 가능  복잡한 syntax 제어 구조에 용이  (defmacro mix-and-match (p q) ;; not destruturing (let ((x1 (first p)) (y1 (second p)) (x2 (first q)) (y2 (second q))) `(list ’(,x1 ,y1) ’(,x1 ,y2) ’(,x2 ,y1) ’(,x2 ,y2))))  (defmacro mix-and-match ((x1 y1) (x2 y2)) ;; destruturing `(list ’(,x1 ,y1) ’(,x1 ,y2) ’(,x2 ,y1) ’(,x2 ,y2)))
  • 15.
    Advanced topics: Destructuring lambdalists - example  DOVECTOR  (defmacro dovector ((var vector-exp &optional result-form) &body body) `(do* ((vec-dov ,vector-exp) (len-dov (length vec-dov)) (i-dov 0 (+ i-dov 1)) (,var nil)) ((equal i-dov len-dov) ,result-form) (setf ,var (aref vec-dov i-dov)) ,@body)) > (dovector (x ’#(foo bar baz)) (format t "~&X is ~S" x)) X is FOO X is BAR X is BAZ NIL  vec-dov, len-dov, i-dov 는 초기값을 담기 위한 지역 변수  변수 이름 충돌을 막기 위해서 package system과 gensyms를 사용하는 것이 바람직하지만 이 책의 범위를 벗어 나는 내용
  • 16.
  • 17.
    Advanced topics: Macros andlexical scoping  함수로 incf 만들기  값이 평가되는 것이 피하기 위해 symbol을 사용함  변수에 대한 Read & Update가 가능해야 함  전역변수는 가능  (defun faulty-incf (var) (set var (+ (symbol-value var) 1))) (setf a 7) > (faulty-incf ’a) 8 > (faulty-incf ’a) 9 > a 9  지역 변수는 매크로만 가능  (defun test-simple (turnip) (simple-incf turnip)) (defun test-faulty (turnip) (faulty-incf ’turnip)) > (test-simple 37) 38 > (test-faulty 37)  Error: TURNIP unassigned variable.  FAULTY-INCF의 부모 lexical-context는 global-context이기 때문에 TEST-FAULTY의 지역변수 TURNIP에 lexically하 게 접근이 되어지지 않는다.
  • 18.
    Advanced topics: Dynamic scoping Lexical scoping  정의  X변수에 접근하기 위해서는 X가 정해진 body 안에서만 접근가능  전역함수  DEFUN으로 정의 되어짐  자신의 local 변수와 전역 변수 접근 가능  지역함수  함수 BAR안에 lambda 표현 식으로 정의  자신의 변수, BAR의 변수와 전역 변수 접근 가능  Dynamic scoping  Dynamic variable은 Special variable이라고도 부름  정의  변수 X가 special로 선언되면 다른 함수의 지역 변수가 될 수 없고 어디서나 접근이 가능  DEFVAR 매크로를 통해 정의될 수 있음
  • 19.
    Advanced topics: Dynamic scoping- example  (defvar birds) ;; bird를 special로 선언 (setf fish ’(salmon tuna)) ;; fish – lexical (setf birds ’(eagle vulture)) ;; birds – special (defun ref-fish () ;; 참조 함수 선언 fish) (defun ref-birds () birds) (ref-fish) => (salmon tuna) ;; top level에서 실행 (ref-birds) => (eagle vulture)  (defun test-lexical (fish) (list fish (ref-fish))) > (test-lexical ’(guppy minnow)) ;; lexical 변수 참조 ((GUPPY MINNOW) (SALMON TUNA)) ;; ref-fish함수 안의 fish는 lexical scoping에 따라 전역 변수 참조  (defun test-dynamic (birds) (list birds (ref-birds))) ;; dynamic 변수 참조 > (test-dynamic ’(robin sparrow)) ;; ref-birds 함수 안의 birds는 dynamic 변수 bird 참조 ((ROBIN SPARROW) (ROBIN SPARROW))  > (ref-birds) (EAGLE VULTURE)  TEST-DYNAMIC의 body로 들어 갈 때 새로운 dynamic 변수 birds가 새기고 TEST-DYNAMIC을 떠날 때 까지 변수 birds는 이값을 참조 하게 됨
  • 20.
    Advanced topics: defvar, defparameter,defconstant  DEFVAR  초기 값 없이 선언 될 수 있음  (defvar *total-glasses*)  한번 그 값이 선언되면 defvar를 통해서 바꿀 수 없음 > (defvar *total-glasses* 0 "Total glasses sold so far") > (defvar *total-glasses* 3 "Total glasses sold so far") > *total-glasses* 0  DEFPARAMETER  초기 값과 함께 선언 되어야 함  (defparameter abc 10)  선언된 값을 defparameter를 통해 바꿀 수 있음 > (defparameter *max-glasses* 500 "Maximum number of glasses we can make") > (defparameter *max-glasses* 300) > *max-glasses* 300  defvar와 defparameter는 똑같은 문법 구조이지만 defparameter는 프로그램이 실행되는 동안 변화되지 않아야 하는 값에 사용  DEFCONSTANT  만들어진 상수는 절대 바뀌지 않음  Lisp의 special valiable들은 관습적으로 *로 둘러 싸서 표현 하지만 defconstant는 예외를 적용  Lisp는 PI와 같은 내장 상수들이 있음
  • 21.
    Advanced topics: Rebinding specialvariables  Function 인자  함수의 인자를 special 변수의 이름으로 지정하여 호출 시 rebinding (defun print-in-base (*print-base* x) (format t "~&~D is written ~S in base ~D." x x *print-base*)) > (print-in-base 2 205) 205 is written 11001101 in base 2. NIL  LET  LET을 통한 바인딩 (defvar *foo* 2) (defun bump-foo () (incf *foo*)) (defun rebind-boo () (let ((*foo* 100)) (incf *foo*) (bump-foo)))
  • 22.
    Ansi Lisp: Macro design– example(1)  ntimes 매크로 만들기  입력된 숫자횟수만큼 반복 실행하는 매크로  (ntimes count &body body)  > (ntimes 10 (princ ".")) .......... NIL  References  ansi lisp  http://onlisp.blogspot.com/2007/12/10-ansi-common-lisp.html
  • 23.
    Ansi Lisp: Macro design– example(2)  ntimes 매크로  (defmacro ntimes (n &rest body) `(do ((x 0 (+ x 1))) ((>= x ,n)) ,@body))  문제점  변수 x를 생성해서 기존에 변수 x가 있었다면 의도치 않은 결과 발생  잘못된 예  (let ((x 10)) (ntimes 5 (setf x (+ x 1))) x) 10  X에 10을 할당하고 그 값을 5번 증가 시켜야 하지만 결과 값은 그대로 10이 됨  매크로 확장  (let ((x 10)) (do ((x 0 (+ x 1))) ((>= x 5)) (setf x (+ x 1))) ;; let으로 생성된 x가 아닌 do안의 변수 x가 증가 x)
  • 24.
    Ansi Lisp: Macro design– example(3)  수정된 ntimes 매크로  do loop안의 변수를 gensym을 통하여 프로그램내의 어느 심볼과도 같지 않게 만듬  (defmacro ntimes (n &rest body) (let ((g (gensym))) `(do ((,g 0 (+ ,g 1))) ((>= ,g ,n)) ,@body)))  문제점  반복 평가  do 문의 body가 평가 될때 마다 n이 새롭게 평가 된다.  잘못된 예  > (let ((v 10)) (ntimes (setf v (- v 1)) (princ "."))) ..... NIL  원하는 결과는 v에서 10에서 1을 뺀 9개의 점을 출력  매크로 확장  (let ((v 10)) (do ((#:g1 0 (+ #:g1 1))) ((>= #:g1 (setf v (- v 1)))) (princ ".")))
  • 25.
    Ansi Lisp: Macro design– example(4)  수정된 ntimes 매크로  (defmacro ntimes (n &rest body) (let ((g (gensym)) (h (gensym))) `(let ((,h ,n)) (do ((,g 0 (+ ,g 1))) ((>= ,g ,h)) ,@body))))  문제점  해결됨
  • 26.