Поиск…


Синтаксис

  • ' Символ , используемый в MACROEXPAND примера просто синтаксический сахар для quote оператора. Вы могли бы написать (macroexpand (quote (infix 1 + 2))) .

замечания

Макросы - это просто функции, которые выполняются во время компиляции, то есть во время шага eval в цикле read-eval-print .

Макросы Reader - это еще одна форма макроса, которая расширяется во время чтения, а не время компиляции.

Лучшая практика при определении макроса.

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

Простой инфиксный макрос

Clojure использует префиксную нотацию, то есть: оператор приходит перед своими операндами.

Например, простая сумма двух чисел:

(+ 1 2)
;; => 3

Макросы позволяют в определенной степени манипулировать языком Clojure. Например, вы можете реализовать макрос, который позволяет писать код в нотации infix (например, 1 + 2 ):

(defmacro infix [first-operand operator second-operand]
    "Converts an infix expression into a prefix expression"
    (list operator first-operand second-operand))

Давайте сломаем то, что делает код выше:

  • defmacro - специальная форма, которую вы используете для определения макроса.
  • infix - это имя макроса, который мы определяем.
  • [first-operand operator second-operand] - это параметры, которые этот макрос ожидает получить, когда он вызывается.
  • (list operator first-operand second-operand) - это тело нашего макроса. Он просто создает list со значениями параметров, предоставляемых макросу infix и возвращает его.

defmacro - особая форма, потому что она ведет себя немного по-другому по сравнению с другими конструкциями Clojure: ее параметры не сразу оцениваются (когда мы называем макрос). Это позволяет нам написать что-то вроде:

(infix 1 + 2)
;; => 3

Макрос infix будет расширять аргументы 1 + 2 на (+ 1 2) , что является допустимой формой Clojure, которую можно оценить.

Если вы хотите увидеть, что генерирует макрос infix , вы можете использовать оператор macroexpand :

(macroexpand '(infix 1 + 2))
;; => (+ 1 2)

macroexpand , как подразумевается его именем, расширит макрос (в этом случае он будет использовать макрос infix для преобразования 1 + 2 в (+ 1 2) ), но не позволит оценить результат макроразложения Переводчик Клоджуре.

Синтаксис цитирования и без комментариев

Пример из стандартной библиотеки ( core.clj: 807 ):

(defmacro and
  "Evaluates exprs one at a time, from left to right. If a form
  returns logical false (nil or false), and returns that value and
  doesn't evaluate any of the other expressions, otherwise it returns
  the value of the last expr. (and) returns true."
  {:added "1.0"}
  ([] true)
  ([x] x)
  ([x & next]
   `(let [and# ~x]
      (if and# (and ~@next) and#))))
  • ` called syntax-quote похожа на (quote) , но рекурсивна: она вызывает (let …) , (if …) и т. д., чтобы не оценивать во время макроразложения, а выводить как есть
  • ~ aka unquote отменяет синтаксис-цитату для отдельной формы внутри синтаксически-цитируемой формы. Таким образом, значение x выводится при расширении макроса (вместо вывода символа x )
  • ~@ aka unquote-splicing похож на unquote, но принимает аргумент списка и расширяет его, каждый элемент списка в отдельной форме
  • # добавляет уникальный идентификатор к символам для предотвращения конфликтов имен. Он добавляет тот же идентификатор для того же символ внутри выражения синтаксических кавычек, так and# внутри let и and# внутри , if получат такое же имя


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow