~~~~~~~~~~~~~~~~~~~~ Arc.Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~ 
Номер скриншота №:
✰ 0AC6100372CE72C8AC971FD6B8AA5CB8__1715624460 ✰
Заголовок документа оригинал.:
✰ Hygienic macro - Wikipedia ✰
Заголовок документа перевод.:
✰ Гигиенический макрос — Википедия ✰
Снимок документа находящегося по адресу (URL):
✰ https://en.wikipedia.org/wiki/Hygienic_macro ✰
Адрес хранения снимка оригинал (URL):
✰ https://arc.ask3.ru/arc/aa/0a/b8/0ac6100372ce72c8ac971fd6b8aa5cb8.html ✰
Адрес хранения снимка перевод (URL):
✰ https://arc.ask3.ru/arc/aa/0a/b8/0ac6100372ce72c8ac971fd6b8aa5cb8__translat.html ✰
Дата и время сохранения документа:
✰ 16.06.2024 10:30:50 (GMT+3, MSK) ✰
Дата и время изменения документа (по данным источника):
✰ 13 May 2024, at 21:21 (UTC). ✰ 

~~~~~~~~~~~~~~~~~~~~~~ Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~~ 
Сервисы Ask3.ru: 
 Архив документов (Снимки документов, в формате HTML, PDF, PNG - подписанные ЭЦП, доказывающие существование документа в момент подписи. Перевод сохраненных документов на русский язык.)https://arc.ask3.ruОтветы на вопросы (Сервис ответов на вопросы, в основном, научной направленности)https://ask3.ru/answer2questionТоварный сопоставитель (Сервис сравнения и выбора товаров) ✰✰
✰ https://ask3.ru/product2collationПартнерыhttps://comrades.ask3.ru


Совет. Чтобы искать на странице, нажмите Ctrl+F или ⌘-F (для MacOS) и введите запрос в поле поиска.
Arc.Ask3.ru: далее начало оригинального документа

Гигиенический макрос — Википедия Jump to content

Гигиенический макрос

Из Википедии, бесплатной энциклопедии

В информатике , гигиенические макросы — это макросы гарантированно не приведет к случайному захвату идентификаторов расширение которых . Они являются особенностью таких языков программирования , как Scheme . [1] Дилан , [2] Раст , Ним и Джулия . Общая проблема случайного захвата была хорошо известна в сообществе Lisp до появления гигиенических макросов. Авторы макросов будут использовать функции языка, которые генерируют уникальные идентификаторы (например, gensym) или использовать запутанные идентификаторы, чтобы избежать проблемы. Гигиенические макросы — это программное решение проблемы захвата, интегрированное в расширитель макросов. Термин «гигиена» был придуман в статье Кольбекера и др. 1986 года, в которой было введено гигиеническое макрорасширение, вдохновленное терминологией, используемой в математике. [3]

Проблема гигиены [ править ]

Переменное затенение [ править ]

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

#define INCI(i) { int a=0;   ++я;   } 
 Int   main  (  void  ) 
 { 
   int   a   =   4  ,   b   =   8  ; 
    ИНЦИ  (  а  ); 
    ИНЦИ  (  б  ); 
    printf  (  "a теперь %d, b теперь %d  \n  "  ,   a  ,   b  ); 
    вернуть   0  ; 
  } 

Выполнение вышеизложенного через препроцессор C дает:

int   main  (  void  ) 
 { 
     int   a   =   4  ,   b   =   8  ; 
      {   интервал   а   =   0  ;    ++  а  ;    }; 
      {   интервал   а   =   0  ;    ++  б  ;    }; 
      printf  (  "a теперь %d, b теперь %d  \n  "  ,   a  ,   b  ); 
      вернуть   0  ; 
  } 

Переменная a объявленный в верхней области видимости затеняется , aпеременная в макросе, которая вводит новую область видимости . Как результат, a никогда не изменяется при выполнении программы, как показывает вывод скомпилированной программы:

А сейчас 4, Б сейчас 9
 

Переопределение функции стандартной библиотеки [ править ]

Проблема гигиены может выходить за рамки привязки переменных. Рассмотрим этот Common Lisp макрос :

(  defmacro   my-unless   (  условие   &body   тело  ) 
  `  (  если   (  не   ,  условие  ) 
     (  progn 
       ,@  тело  ))) 

Хотя в этом макросе нет ссылок на переменные, он предполагает, что символы «if», «not» и «progn» привязаны к своим обычным определениям в стандартной библиотеке. Однако если приведенный выше макрос используется в следующем коде:

(  flet   ((  not   (  x  )   x  )) 
   (  my-unless   t 
     (  format   t   "Это не следует печатать!"  ))) 

Определение «не» было локально изменено, поэтому расширение my-unless изменения.

Однако обратите внимание, что для Common Lisp такое поведение запрещено в соответствии с разделом 11.1.2.1.2 «Ограничения пакета COMMON-LISP для соответствующих программ» . В любом случае также возможно полностью переопределить функции. Некоторые реализации Common Lisp обеспечивают блокировку пакетов , чтобы предотвратить ошибочное изменение определений в пакетах пользователем.

Переопределение программно-определяемой функции [ править ]

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

(  defun   определяемый пользователем оператор   (  cond  ) 
   (  not   cond  )) 

 (  defmacro   my-unless   (  условие   &body   body  ) 
  `  (  if   (  определяемый пользователем оператор   ,  условие  ) 
     (  progn 
       ,@  body  ))) 

 ;   ... позже ... 

 (  flet   ((  определяемый пользователем оператор   (  x  )   x  )) 
   (  my-unless   t 
     (  format   t   "Это не следует печатать!"  ))) 

Сайт использования переопределяет user-defined-operator и, следовательно, меняет поведение макроса.

используемые в языках, в которых отсутствуют макросы Стратегии , гигиенические

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

Обфускация [ править ]

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

#define INCI(i) { int INCIa = 0;   ++я;   } 
 Int   main  (  void  ) 
 { 
     int   a   =   4  ,   b   =   8  ; 
      ИНЦИ  (  а  ); 
      ИНЦИ  (  б  ); 
      printf  (  "a теперь %d, b теперь %d  \n  "  ,   a  ,   b  ); 
      вернуть   0  ; 
  } 

Пока переменная с именем INCIa создано, это решение дает правильный результат:

А сейчас 5, Б сейчас 9
 

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

Создание временного символа [ править ]

В некоторых языках программирования можно создать новое имя переменной или символ и привязать его к временному местоположению. Система языковой обработки гарантирует, что оно никогда не будет конфликтовать с другим именем или местоположением в среде выполнения. Ответственность за использование этой функции в теле определения макроса остается за программистом. Этот метод использовался в MacLisp , где функция с именем gensymможет использоваться для создания нового имени символа. Подобные функции (обычно называемые gensym также) существуют во многих Lisp-подобных языках, включая широко реализованный Common Lisp. стандарт [4] и Элисп .

Хотя создание символов решает проблему затенения переменных, оно не решает напрямую проблему переопределения функции. [5] Однако, gensym, возможностей макросов и стандартных библиотечных функций достаточно для встраивания гигиеничных макросов в негигиеничный язык. [6]

Неинтернированный символ времени чтения [ править ]

Это похоже на обфускацию, поскольку одно имя используется несколькими расширениями одного и того же макроса. Однако, в отличие от необычного имени, используется неинтернированный символ времени чтения (обозначается #: нотации), для которых невозможно произойти вне макроса, аналогично gensym.

Пакеты [ править ]

При использовании таких пакетов, как Common Lisp, макрос просто использует закрытый символ из пакета, в котором определен макрос. Символ не будет случайно встречаться в коде пользователя. Пользовательский код должен будет проникнуть внутрь пакета, используя двойное двоеточие ( ::) нотация, чтобы дать себе разрешение на использование частного символа, например cool-macros::secret-sym. В этот момент вопрос случайного отсутствия гигиены становится спорным. Более того, стандарт ANSI Common Lisp классифицирует переопределение стандартных функций и операторов, глобально или локально, как вызов неопределенного поведения . Таким образом, такое использование может быть диагностировано реализацией как ошибочное. Таким образом, система пакетов Lisp обеспечивает жизнеспособное и полное решение проблемы гигиены макросов, которую можно рассматривать как пример конфликта имен.

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

Литеральные объекты [ править ]

В некоторых языках расширение макроса не обязательно должно соответствовать текстовому коду; вместо того, чтобы расширяться до выражения, содержащего символ f, макрос может создать расширение, содержащее фактический объект, на который ссылается f. Аналогично, если макросу необходимо использовать локальные переменные или объекты, определенные в пакете макроса, он может расшириться до вызова замыкающего объекта, лексическое окружение которого соответствует определению макроса.

Гигиеническая трансформация

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

Например, схема let-syntax и define-syntax Системы создания макросов гигиеничны, поэтому следующая схема реализации my-unless будет иметь желаемое поведение:

(  define-syntax   my-unless 
   (  синтаксические правила   () 
     ((  _   условия   тело   ...  ) 
      (  if   (  не   условие  ) 
          (  начало   тела   ...  ))))) 

 (  let   ((  not   (  лямбда   (  x  )   x  ))) 
   (  my-unless   #t 
     (  отобразить   «Это не следует печатать!»  ) 
     (  новая строка  ))) 

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

Реализации [ править ]

Макросистемы, которые автоматически обеспечивают соблюдение гигиены, созданы Scheme. Оригинальный алгоритм KFFD для гигиенической макросистемы был представлен Кольбекером в 1986 году. [3] В то время в реализациях Scheme не использовалась стандартная макросистема. Вскоре после этого, в 1987 году, Кольбекер и Ванд предложили декларативный язык на основе шаблонов для написания макросов, который был предшественником языка syntax-rules макросредство, принятое стандартом R5RS. [1] [7] Синтаксические замыкания, альтернативный гигиенический механизм, были предложены Боуденом и Рисом в качестве альтернативы системе Кольбекера и др. в '88. [8] В отличие от алгоритма KFFD, синтаксические замыкания требуют от программиста явного указания разрешения области идентификатора. В 1993 году Дибвиг и др. представил syntax-case макросистема, которая использует альтернативное представление синтаксиса и автоматически поддерживает гигиену. [9] syntax-case система может выражать syntax-rulesязык шаблонов как производный макрос. Термин «макросистема» может быть неоднозначным, поскольку в контексте схемы он может относиться как к конструкции сопоставления с образцом (например, синтаксические правила), так и к структуре для представления и управления синтаксисом (например, синтаксический регистр, синтаксические замыкания). .

Синтаксические правила [ править ]

Синтаксические правила — это высокоуровневое средство сопоставления с образцом , которое пытается упростить написание макросов. Однако, syntax-rulesне способен кратко описать определенные классы макросов и недостаточен для выражения других макросистем. Правила синтаксиса описаны в документе R4RS в приложении, но не являются обязательными. Позже R5RS принял его в качестве стандартного средства макросов. Вот пример syntax-rules макрос, меняющий местами значения двух переменных:

(  замена синтаксиса определения   ! 
   (  правила синтаксиса   () 
     ((  _   a   b  ) 
      (  let   ((  temp   a  )) 
        (  set!   a   b  ) 
        (  set!   b   temp  ))))) 

Синтаксис-кейс [ править ]

Из-за недостатков чисто syntax-rules на основе макросистемы, стандарт схемы R6RS принял макросистему синтаксического регистра. [10] В отличие от syntax-rules, syntax-caseсодержит как язык сопоставления с образцом, так и низкоуровневые средства для написания макросов. Первый позволяет писать макросы декларативно, а второй позволяет реализовать альтернативные интерфейсы для написания макросов. Приведенный выше пример обмена практически идентичен syntax-case потому что язык сопоставления с образцом аналогичен:

(  замена синтаксиса определения   ! 
   (  лямбда   (  stx  ) 
     (  синтаксис-case   stx   () 
       ((  _   a   b  ) 
        (  синтаксис 
         (  let   ((  temp   a  )) 
           (  set!   a   b  ) 
           (  set!   b   temp  ))))) )) 

Однако, syntax-caseболее мощный, чем правила синтаксиса. Например, syntax-caseМакросы могут указывать дополнительные условия в своих правилах сопоставления с образцом с помощью произвольных функций Scheme. В качестве альтернативы автор макросов может отказаться от использования интерфейса сопоставления с образцом и напрямую манипулировать синтаксисом. Используя datum->syntax макросы синтаксического регистра также могут намеренно захватывать идентификаторы, нарушая тем самым гигиену.

Другие системы [ править ]

Для Scheme также были предложены и реализованы другие макросистемы. Синтаксические замыкания и явное переименование [11] две альтернативные макросистемы. Обе системы являются более низкими уровнями, чем правила синтаксиса, и оставляют соблюдение гигиены на усмотрение автора макросов. Это отличается как от синтаксических правил, так и от синтаксических регистров, которые по умолчанию автоматически обеспечивают соблюдение гигиены. Приведенные выше примеры замены показаны здесь с использованием синтаксического замыкания и явной реализации переименования соответственно:

;;   синтаксические замыкания 
 (  define-syntax   swap! 
    (  sc-macro-transformer 
     (  лямбда   (  формы   среда  ) 
       (  let   ((  a   (  close-syntax   (  cadr   form  )   среда  ) 
             (  b   (  среда close-syntax   (  cadr   form  )   ) )  )) 
         `  (  let   ((  temp   ,  a  )) 
            (  set!   ,  a   ,  b  ) 
            (  set!   ,  b   temp  )))))) 

 ;;   явное переименование 
 (  define-syntax   swap! 
  (  er-macro-transformer 
   (  лямбда   (  form   rename   Compare  ) 
     (  let   ((  a   (  cadr   form  )) 
           (  b   (  cadr   form  )) 
           (  temp   (  rename   'temp  ))) 
       `  (  ,  (  переименовать   'let  )   ((  ,  temp   ,  a  )) 
            (  ,  (  переименовать   ' набор!  )   ,  a   ,  b  ) 
            (  ,  (  переименовать   ' набор!  )   ,  b   ,  temp  )))))) 

Языки с гигиеническими макросистемами [ править ]

Критика [ править ]

Гигиеничные макросы обеспечивают безопасность и ссылочную прозрачность за счет того, что преднамеренный захват переменных становится менее простым. Дуг Хойт, автор книги Let Over Lambda , пишет: [16]

Почти все подходы, применяемые для уменьшения влияния захвата переменных, служат только для уменьшения того, что вы можете сделать с помощью defmacro. Гигиенические макросы в лучших ситуациях являются ограждением безопасности для новичка; в худших ситуациях они образуют электрический забор, запирая своих жертв в продезинфицированной и безопасной тюрьме.

Дуг Хойт

Многие гигиенические макросистемы предлагают аварийные люки без ущерба для гарантий, обеспечиваемых гигиеной; например, Racket позволяет вам определять параметры синтаксиса , которые позволяют выборочно вводить связанные переменные. Грегг Хендершотт приводит пример в книге «Страх перед макросами». [17] реализации анафорического оператора if таким способом.

См. также [ править ]

Примечания [ править ]

  1. ^ Перейти обратно: а б Келси, Ричард; Клингер, Уильям; Рис, Джонатан; и другие. (август 1998 г.). «Пересмотренный 5 Отчет об алгоритмической языковой схеме» . Высшие порядки и символические вычисления . 11 (1): 7–105. doi : 10.1023/A:1010051815785 .
  2. ^ Фейнберг, Н.; Кин, ЮВ; Мэтьюз, РОД; Withington, PT (1997), Программирование Дилана: объектно-ориентированный и динамический язык , Addison Wesley Longman Publishing Co., Inc.
  3. ^ Перейти обратно: а б Кольбекер, Э.; Фридман, ДП; Феллейзен, М.; Дуба, Б. (1986). «Гигиеническое макрорасширение» (PDF) . Конференция ACM по LISP и функциональному программированию .
  4. ^ «CLHS: Функция GENSYM» .
  5. ^ «гигиена против генсима» . Community.schemewiki.org . Проверено 11 июня 2022 г.
  6. ^ Костанца, Паскаль; Д'Ондт, Тео (2010). «Встраивание гигиенически совместимых макросов в негигиеническую макросистему» . Журнал универсальной информатики . 16 (2): 271–295. CiteSeerX   10.1.1.424.5218 . дои : 10.3217/jucs-016-02-0271 .
  7. ^ Кольбекер, Э.; Ванд, М. (1987). «Макрос на примере: получение синтаксических преобразований на основе их спецификаций» (PDF) . Симпозиум по основам языков программирования .
  8. ^ Bawden, A.; Rees, J. (1988). "Syntactic closures" (PDF). Lisp and Functional Programming. Archived (PDF) from the original on September 3, 2019.
  9. ^ Дыбвиг, К; Хиеб, Р; Бругерман, К. (1993). «Синтаксическая абстракция в схеме» (PDF) . LISP и символьные вычисления . 5 (4): 295–326. дои : 10.1007/BF01806308 . S2CID   15737919 .
  10. ^ Спербер, Майкл; Дибвиг, Р. Кент; Флэтт, Мэтью; Ван Страатен, Антон; и другие. (август 2007 г.). «Пересмотренный 6 Отчет о схеме алгоритмического языка (R6RS)» . Руководящий комитет схемы . Проверено 13 сентября 2011 г.
  11. ^ Клингер, Уилл (1991). «Гигиеничные макросы за счет явного переименования». Указатели Lisp ACM SIGPLAN . 4 (4): 25–28. дои : 10.1145/1317265.1317269 . S2CID   14628409 .
  12. ^ Скальски, К.; Москаль, М; Ольшта, П. Метапрограммирование в Nemerle (PDF) , заархивировано из оригинала (PDF) 13 ноября 2012 г.
  13. ^ «Макросы» .
  14. ^ «Метапрограммирование: язык Джулии» . Архивировано из оригинала 4 мая 2013 г. Проверено 03 марта 2014 г.
  15. ^ «Краткий обзор 6: Подпрограммы» . Архивировано из оригинала 6 января 2014 г. Проверено 3 июня 2014 г.
  16. ^ [1] , Let Over Lambda — 50 лет Lisp Дуг Хойт
  17. ^ [2] , Боязнь макросов

Ссылки [ править ]

Arc.Ask3.Ru: конец оригинального документа.
Arc.Ask3.Ru
Номер скриншота №: 0AC6100372CE72C8AC971FD6B8AA5CB8__1715624460
URL1:https://en.wikipedia.org/wiki/Hygienic_macro
Заголовок, (Title) документа по адресу, URL1:
Hygienic macro - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть, любые претензии не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, денежную единицу можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)