2012-11-15 2 views
2

매크로와 함수의 차이점에 대해 혼란스러워합니다. 특히 PART ONE이 성공한 경우 PART TWO가 아래에서 실패하는 이유.Common Lisp [sbcl]의 변수에 매크로를 저장하는 방법은 무엇입니까?

(defun foo() "foo") 
(setf a 3) ;; sets the symbol value cell to 3 
(setf a #'foo) ;; PART ONE 
(funcall a) ;; returns foo 

(defmacro bar() "bar") 
(setf b #'bar) ;; Error the macro name bar was found as an argument to function PART TWO 

답변

2

# (sharpsign)은 표준 매크로 문자로 디스패치 매크로 문자입니다. 다른 캐릭터와 작곡하기로되어 있습니다. #' (sharpsign single-quote) 조합 뒤에 함수 이름 또는 람다식이 필요하며 (function expression)으로 확장됩니다.

따라서 #'foo은 읽기 시간이 (function foo)으로 확장됩니다. foo이 함수 인 경우 function이 계산됩니다. 어휘 범위에서는 foo fbound가 flet or labels 일 수 있습니다. 그러한 어휘 정의가 없다면 심볼 함수에서 전역 함수 정의를 가져 오려고합니다. bar 매크로를 나타내는 경우

지금, (function bar) 에러 신호, 그것을 어휘 macrolet 또는 글로벌 defmacro에게 될. 그러나 bar 매크로의 매크로 함수를 가져 오는 데 (macro-function 'bar)을 사용할 수 있습니다. 존재하는 경우, 두 가지 인수, 즉 양식과 환경의 함수입니다.

bar의 매크로 기능을 양식에 적용하지 않는 한, 사용자가 원하는 것이 아닐 수 있습니다. and의 매크로 함수를 적용하는 것에 대해 생각해 봅시다 : 논리 부울 연산을 수행하지 않고 주어진 양식을 if으로 확장합니다.

그러나 이것이 원하는 경우 macro-function에는 두 번째 선택적 매개 변수 인 환경이 있다는 것을 기억하십시오. defmacro 또는 define-setf-expander에 환경을 인수로 가져올 수 있습니다. 후자의 경우에는 일반적으로 get-setf-expansion이 하위 양식을 확장 할 때 어휘 환경을 고려해야합니다.

이 밖으로 시도 :

(funcall (macro-function 'and) '(and form1 form2 form3) nil) 

운동을 : 당신의 자신의 macroexpand-1 and macroexpand를 구현합니다.

연습 : Common Lisp의 특수 연산자를 인식하여 서브 폼으로 되풀이되는 macroexpand-all, macroexpand을 구현하십시오.

참고 : macroexpand-all으로 너무 멀리 가지 마세요. 구현에 따라 코드 워커가 필요합니다.

+0

질문에 대한 나의 원래 의도는 다음과 같이 수행 할 수 있습니다. (setf (매크로 함수 'sym1) (매크로 함수'막대)) – tjb

1

그 이유는 매크로를 사용하면 기능 (#'foo 심볼 foo에 해당하는 함수 객체를 가져 (function foo)위한 속기이다)에로 참조 할 수 있도록 기능을하지 않습니다, 그리고 당신 funcall 수 없습니다.

부분적 해결책은 (setf b (lambda() (bar)))이 작동하는 매크로에서 매크로를 래핑하는 것입니다. 마찬가지로 funcall입니다. 그러나 매크로에서 &rest/&body 인수가 필요하면 작동하지 않습니다. 이 경우 달성하려는 일반적인 방법은 없습니다. 따라서 귀하는 귀하의 접근 방식을 재고해야합니다. 질문 : 왜 funcall 매크로를 시도하고 있습니까? 어쩌면 평범한 기능이 당신의 경우에 도움이 될까요?

7

매크로는 기능이 아닙니다. 따라서 매크로 이름에서 함수 객체를 가져올 수 없습니다. 함수는 적용 할 수 있지만 매크로는 적용 할 수 없습니다.

매크로는 소스 코드를 예상하고 새로운 소스 코드를 생성합니다.

Common Lisp는 컴파일 타임에 런타임 전에 수행 할 수있는 방식으로 정의됩니다. Common Lisp은 일반적으로 런타임 매크로 확장을 지원하지 않습니다. Common Lisp은 그렇게하기 전에 코드가 실행되기 전에 완전히 컴파일 될 수 있도록합니다. Common Lisp을 정의 할 때 목표 중 하나는 큰 Lisp 프로그램을 효율적으로 실행할 수있는 언어로 정의하는 것이 었습니다. 런타임 코드 생성은 제어 된 방식으로 만 유용합니다. 그렇지 않으면 런타임에 완전히 새로운 클래스의 실행 오류가 발생할 수 있습니다. 일반적인 런타임 코드 조작을 허용하는 매크로 메커니즘은 바람직하지 않은 것으로 보입니다.

예전의 Lisp 언어에는 FEXPRs이라는 아이디어가있었습니다.이 매크로는 런타임에 호출 할 수 있고 런타임으로 소스를 조작 할 수있는 매크로와 비슷합니다. 이 기능은 Common Lisp에서 제거되었습니다. 이에 대한 배경은 Kent Pitman의 Special Forms in Lisp을 참조하십시오.

0

'컴파일러 플러그인'으로 매크로가 도움이 될 수 있습니다. 자, 컴파일러의 일부를 변수에 저장하는 것이 합리적일까요? 아니요 (Lisp조차도 아닙니다).

관련 문제