Знание того, на что вы смотрите, должно быть макросом - PullRequest
3 голосов
/ 26 марта 2019

Я знаю, что есть macro-function, объяснено здесь , которое позволяет вам проверять, но возможно ли просто при чтении исходного кода lisp иногда делать вывод о том, на что вы смотрите " это должен быть макрос "? (при условии, конечно, что вы никогда раньше не видели функцию / макрос).

Я вполне уверен, что ответ - да, но, поскольку это кажется настолько фундаментальным, я подумал, стоит спросить, особенно потому, что любые нюансы по этому поводу могут быть ценными и интересными.

В ANSI Common Lisp Пола Грэма, стр. 70, он описывает, как использовать defstruct.

Когда я вижу (defstruct point x y), если бы я абсолютно ничего не знал о том, что такое defstruct, это вполне могло бы быть функцией.

Но когда я вижу

(defstruct polemic
  (subject "foo")
  (effect  "bar"))

Я знаю, что должен быть макросом, потому что (предположим), я также знаю, что subject и effect являются неопределенными функциями. (Я знаю , что , потому что они ошибаются с undefined function при вызове «на верхнем уровне» (?)) (Если это правильный термин).

Если бы два аргумента списка в defstruct были указаны, это было бы не так просто. Поскольку они не указаны, это должен быть макрос.

Это так просто?

Я немного изменил имена полей по сравнению с теми, что использовались в книге, чтобы прояснить этот вопрос.

Наконец, Грэм пишет:

«Мы можем указать значения по умолчанию для структурных полей, заключив имя поля и выражение по умолчанию в список в исходном определении»

Что я замечаю, так это то, что это правда, но это не (цитируемый) список. Если бы кто-то из читателей этого поста сформулировал вышеприведенное предложение по-другому (учитывая, что макросы еще не были введены в книгу (хотя у меня есть базовое представление о том, что они из себя представляют)).

Мне кажется, что это не "список данных", в которые заключены выражения по умолчанию. (Извинения за плохую терминологию) - поиск правильной концепции здесь.

Ответы [ 2 ]

4 голосов
/ 26 марта 2019

В общем, вы правы: если внутри вызова есть некоторая вложенность, и вы уверены, что машина из вложенных списков не является функцией - это макрос.

Кроме того, почти всегда, def -что-то и with -что-то - это макросы.

Но гарантии нет.Вопрос в том, чего вы пытаетесь достичь?Некоторый ход кода / преобразование или внешняя обработка (как в редакторе).Что касается последнего, вам следует помнить, что полный контроль возможен только в том случае, если вы выполняете оценку кода, хотя эвристика (как в Emacs) может привести вас довольно далеко.Или вы просто хотите развить свою интуицию для более быстрого чтения кода ...

3 голосов
/ 26 марта 2019

Существует ряд соглашений, которые довольно четко определяют, какие формы должны быть макросами, просто имитируя синтаксис существующих макросов или специальных операторов CL.Например, следующее представляет собой смесь различных воображаемых макросов, но даже не зная их определения, код не должен быть слишком сложным для понимания:

(defun/typed example ((id (integer 0 10)))
  (with-connection (connection (connect id))
    (do-events (event connection)
      (event-case event
        (:quit (&optional code) (return code))))))

Обычный совет о макросах - избегать ихесли возможно, поэтому, если вы заметите что-то, что не имеет смысла, в качестве выражения lisp, это, вероятно, макрос или вложенный в него макрос.

(defstruct point x y)

[...] где яЧтобы ничего не знать о том, что такое defstruct, это может быть и функция.

Существуют различные намеки, что это не функция.Прежде всего, имя начинается с def.Тогда, если бы defstruct была функцией, то перед вызовом функции все значения point, x и y будут оцениваться, и это означает, что код будет полагаться на глобальные переменные, даже если они не носят вкладыши(например, *point*, *x*, *y*), и вы, вероятно, не найдете их определения в предыдущих формах (или позже в том же модуле компиляции).Кроме того, если бы это была функция, результат был бы отброшен напрямую, поскольку он не используется (это форма верхнего уровня).Это только указывает на возможное наличие побочных эффектов, но все же это было бы необычно.Функция верхнего уровня с побочными эффектами выглядела бы так вместо этого с данными в кавычках:

(register-struct 'point '(x y))

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

(my-get object :slot)

Это может быть вызов функции, или у вас может быть макрос, который преобразует вышеприведенное значение в (aref object 0) (при условии, что :slot - нулевая ячейка в объекте, поскольку предполагается, что все ваши объекты имеютопределенный пользовательский тип, поддерживаемый вектором).Вы также можете иметь макросы компилятора.В случае сомнений попробуйте макрорасширить его и посмотреть документацию.

...