원하는 것을하는 매크로
일종의 연습으로 :
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE."
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
이제 시도해보십시오.
(setq-every "/foo/bar" f-loc1 f-loc2)
작동 원리
사람들은 그것이 어떻게 작동하는지 궁금하기 때문에 (설명에 따라) 여기에 설명이 있습니다. 매크로를 작성하는 방법을 배우려면 좋은 Lisp 책을 선택하십시오 (예, Common Lisp, Emacs Lisp에서도 동일한 작업을 수행 할 수 있지만 Common Lisp은 조금 더 강력하고 더 나은 책을 가지고 있습니다) IMHO.
매크로는 원시 코드에서 작동합니다. 매크로는 함수와 달리 인수를 평가하지 않습니다. 그래서 우리는 여기에 대한 평가되지 않은 value
컬렉션을 가지고 있습니다 vars
.
progn
여러 setq
양식을 하나로 그룹화합니다 . 이건 :
(mapcar (lambda (x) (list 'setq x value)) vars)
setq
OP의 예를 사용하여 양식 목록을 생성 하면됩니다.
((setq f-loc1 "/foo/bar") (setq f-loc2 "/foo/bar"))
보시다시피, 양식은 역 따옴표 양식 안에 있으며 앞에 쉼표가 붙습니다
,
. 내부 인용 된 양식은 모든 것이 일반적으로 인용되지만 ,
일시적으로 "켜짐"평가되므로 전체 mapcar
가 거시 확장 시간에 평가됩니다.
마지막으로 s를 사용하여 @
목록에서 외부 괄호를 제거 setq
하여 다음을 얻습니다.
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
매크로는 소스 코드를 임의로 변형시킬 수 있습니다.
경고
다음은 작은 경고입니다.이 매크로는 본질적으로 다음과 같이 확장되기 때문에 첫 번째 인수는 여러 번 평가됩니다.
(progn
(setq f-loc1 "/foo/bar")
(setq f-loc2 "/foo/bar"))
여기에 변수 또는 문자열이 있으면 괜찮지 만 다음과 같이 작성하면됩니다.
(setq-every (my-function-with-side-effects) f-loc1 f-loc2)
그런 다음 함수가 두 번 이상 호출됩니다. 바람직하지 않을 수 있습니다. 다음은 MMT 패키지once-only
에서 사용 가능
하도록 수정하는 방법입니다 .
(defmacro setq-every (value &rest vars)
"Set every variable from VARS to value VALUE.
VALUE is only evaluated once."
(mmt-once-only (value)
`(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars))))
그리고 문제는 사라졌습니다.