Может ли кто-нибудь объяснить мне понятие "гигиена" (я программист)?

Итак... Я новичок в схеме r6rs и изучаю макросы. Может кто-нибудь объяснить мне, что означает "гигиена"?

Заранее спасибо.

6 ответов

Решение

Гигиена часто используется в контексте макросов. Гигиенический макрос не использует имена переменных, которые могут помешать расширению кода. Вот пример. Допустим, мы хотим определить or специальная форма с макросом. Наглядно,

(or a b c ... d) будет расширяться до чего-то вроде (let ((tmp a)) (if tmp a (or b c ... d))), (Я опускаю пустое (or) случай для простоты.)

Теперь, если имя tmp фактически был добавлен в код, как в приведенном выше наброске, это было бы не гигиенично, а плохо, потому что это могло бы помешать другой переменной с тем же именем. Скажем, мы хотели оценить

(let ((tmp 1)) (or #f tmp))

Используя наше интуитивное расширение, это станет

(let ((tmp 1)) (let ((tmp #f)) (if tmp (or tmp)))

tmp из макро-теней самый внешний tmpи так результат #f вместо 1,

Теперь, если макрос был гигиеническим (и в схеме, это автоматически происходит при использовании syntax-rules), то вместо использования имени tmp для расширения вы должны использовать символ, который гарантированно не появится где-либо еще в коде. Ты можешь использовать gensym в Common Lisp.

В "On Lisp" Пола Грэма есть продвинутый материал по макросам.

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

Это не a что ты хочешь!

Макросистема, в которой нечто подобное не может произойти, называется гигиенической.

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

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

И, как я сказал, в гигиенической макросистеме такие столкновения не могут происходить в первую очередь. Как сделать гигиеническую систему макросов - интересный вопрос сам по себе, и сообщество Scheme потратило несколько десятилетий на этот вопрос, и они продолжают придумывать лучшие и лучшие способы сделать это.

Я так рад узнать, что этот язык все еще используется! Гигиенический код - это код, который при введении (через макрос) не вызывает конфликтов с существующими переменными.

В Википедии есть много полезной информации об этом: http://en.wikipedia.org/wiki/Hygienic_macro

Макросы преобразуют код: они берут один бит кода и превращают его во что-то другое. В рамках этого преобразования они могут окружить этот код большим количеством кода. Если исходный код ссылается на переменную aи код, который добавлен вокруг него, определяет новую версию a, тогда исходный код не будет работать должным образом, потому что он будет обращаться к неправильному a: если

(myfunc a)

это оригинальный код, который ожидает a быть целым числом, а макрос принимает X и превращает его в

(let ((a nil)) X)

Тогда макрос будет нормально работать для

(myfunc b)

но (myfunc a) будет преобразован в

(let ((a nil)) (myfunc a))

который не будет работать, потому что myfunc будет применяться к nil а не целое число, которое он ожидает.

Гигиенический макрос позволяет избежать этой проблемы, связанной с обращением к неверной переменной (и аналогичной проблемы, наоборот), обеспечивая уникальность используемых имен.

В Википедии есть хорошее объяснение гигиенических макросов.

Помимо всего перечисленного, в гигиенических макросах Схемы есть еще одна важная вещь, вытекающая из лексического контекста.

Скажем, у нас есть:

(syntax-rules () ((_ a b) (+ a b)))

Как часть макроса, он обязательно вставит +, он также вставит его, когда уже есть +, но затем другой символ, который имеет то же значение, что и +, Он связывает символы со значением, которое они имели в лексической среде, в которой syntax-rules ложь, а не там, где она применяется, в конце концов, мы ограничены лексической областью. Скорее всего, он вставит туда совершенно новый символ, но глобально связанный с тем же значением, что и + находится в месте, где определен макрос. Это наиболее удобно, когда мы используем такую ​​конструкцию, как:

(let ((+ *))
  ; piece of code that is transformed
)

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

Вот что я нашел. Объяснение того, что это значит, совсем другое дело!

http://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-1.html

Другие вопросы по тегам