Сделайте макросы и функции более интегрированными - PullRequest
6 голосов
/ 02 июля 2010

ОК, я прекрасно понимаю, как использовать функцию и макросы.

Что меня интересует, так это то, почему компилятор не может быть немного более умным при интеграции двух, например рассмотрим код 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

Да, я знаю, что могу сделать эту работу, убрав «apply» - но почему компилятор не может понять, как это сделать самому?

Возможно ли в Clojure / других LISP создать версию apply или другие функции более высокого порядка, которые одинаково хорошо работают как с функциями, так и с макросами в качестве параметров?

Ответы [ 2 ]

11 голосов
/ 02 июля 2010

Этот ответ не столько о Clojure, сколько о Lisp и макросах в целом.

Помните:

APPLY позволяет вызывать функции со списками аргументов, которые создаются во время выполнения.

Существуют макросы для генерации нового исходного кода из некоторого исходного кода - и сгенерированный исходный код будет работать.

Сейчас:

Если вы разрешите применять для подачи другого исходного кода в макрос во время выполнения, необходимо иметь возможность генерировать код результата во время выполнения, а также выполнять сгенерированный код.

Таким образом, в скомпилированной системе Lisp каждый вызов APPLY с макросом потенциально создает новый код, который должен быть скомпилирован во время выполнения, чтобы иметь возможность его выполнить. Это также означает, что вы можете получить новые ошибки компилятора во время выполнения, когда ваш код выполняется, и у кода есть некоторые проблемы. Поэтому для ПРИМЕНЕНИЯ макросов во время выполнения вам необходим компилятор и вся необходимая информация (например, другие макросы), чтобы иметь возможность расширять и компилировать код.

Это также означает, что в общем случае вы не можете скомпилировать APPLY с макросом до времени выполнения, так как неизвестно, какие аргументы времени выполнения будут применены.

В Lisp на основе интерпретатора может быть больше информации, и макросы можно применять постоянно.

В раннем Лиспе были обычные функции и так называемые FEXPR. FEXPR позволяли гибко управлять вызовами и манипулировать кодом во время выполнения. Позже в истории Lisp они были заменены макросами, так как макросы обеспечивают эффективную компиляцию, а в системах на основе компилятора позволяют обрабатывать синтаксические ошибки перед выполнением.

2 голосов
/ 02 июля 2010

То, что вы описываете, звучит как макрос первого класса (то есть: макрос, которым вы можете манипулировать как функция). У некоторых lisps они есть (например, Arc ), но apply из-за того, что сам не является макросом, вероятно, все равно не будет работать.

...