6

좋아, 나는 함수와 매크로를 모두 사용하는 방법을 잘 알고있다.매크로와 함수를 더 매끄럽게 만들기

내가 궁금한 점은 왜 두 가지를 통합 할 때 컴파일러가 더 영리하지 못하다는 것입니다. Clojure의 코드를 고려해

(defmacro wonky-add [a b] `(+ ~a (* 2 ~b))) 

(defn wonky-increment [a] (apply wonky-add a 1)) 
=> Error: can't take value of a macro 

예, 나는 "적용"복용하여이 작업을 할 수있어 -하지만 왜 컴파일러는이 자체 작업을 수행하는 방법을 알아낼 수 있다는 것입니다?

Clojure/다른 LISP에서 함수와 매크로 모두 매개 변수로 동등하게 잘 적용되는 적용 또는 다른 고차 함수 버전을 만들 수 있습니까?

답변

11

이 답변은 Clojure에 관한 것이 아니라 일반적으로 Lisp 및 매크로에 관한 내용입니다.

가 기억

가 적용 런타임에 생성 인자 목록과 함수를 호출 할 수있을 것입니다.

매크로는 일부 소스 코드에서 새 소스 코드를 생성합니다. 생성 된 소스 코드가 실행됩니다. 이제

: 런타임에서 매크로에 다른 소스 코드를 공급하기 위해 적용 할 수있는 경우

, 하나는 런타임에 결과 코드를 생성 할 수 있어야하고 또한 생성 된 코드를 실행합니다.

따라서 컴파일 된 Lisp 시스템에서 매크로를 사용하는 모든 APPLY 호출은 런타임에 컴파일 할 필요가있는 새 코드를 잠재적으로 만들 수 있습니다. 즉, 런타임에 코드가 실행되고 코드에 문제가있을 때 새로운 컴파일러 오류가 발생할 수 있습니다. 따라서 런타임에 매크로를 적용하려면 코드를 확장하고 컴파일 할 수 있도록 컴파일러와 필요한 모든 정보 (예 : 다른 매크로)가 필요합니다.

이것은 또한 런타임 인수가 적용될 것으로 알려지지 않았기 때문에 일반적으로 런타임 이전에 매크로로 APPLY를 컴파일 할 수 없음을 의미합니다.

인터프리터 기반 Lisp에서는 더 많은 정보와 매크로가 항상 적용될 수 있습니다.

초기 Lisp에는 정상적인 기능과 소위 FEXPR이있었습니다. FEXPR은 유연한 호출 및 런타임 코드 조작을 허용했습니다. 나중에 Lisp의 역사에서 매크로는 매크로로 대체되었는데 매크로는 효율적인 컴파일을 허용하고 컴파일러 기반 시스템에서는 런타임 전에 구문 오류를 처리 할 수 ​​있기 때문입니다.

2

당신이 말하는 것은 1 등석 매크로 (예 : 함수처럼 조작 할 수있는 매크로)처럼 들릴 수 있습니다. 어떤 리스프에는이 (Arc)이 있지만, 매크로 자체가 아니기 때문에 apply은 여전히 ​​작동하지 않습니다.

관련 문제