Что делает макросы Lisp такими особенными? - PullRequest
280 голосов
/ 06 ноября 2008

Чтение Эссе Пола Грэма о языках программирования можно подумать, что Макросы Lisp - единственный путь. Как занятый разработчик, работающий на других платформах, я не имел права использовать макросы Lisp. Как человек, который хочет понять гул, пожалуйста, объясните, что делает эту функцию такой мощной.

Пожалуйста, также свяжите это с тем, что я бы понял из миров разработки на Python, Java, C # или C.

Ответы [ 14 ]

5 голосов
/ 06 ноября 2008

Короче говоря, макросы - это преобразования кода. Они позволяют вводить много новых синтаксических конструкций. Например, рассмотрим LINQ в C #. В lisp есть похожие языковые расширения, которые реализуются макросами (например, встроенная конструкция цикла, итерация). Макросы значительно уменьшают дублирование кода. Макросы позволяют встраивать «маленькие языки» (например, когда в c # / java для настройки используется xml, в lisp то же самое может быть достигнуто с помощью макросов). Макросы могут скрыть трудности использования библиотек.

Например, в lisp можно написать

(iter (for (id name) in-clsql-query "select id, name from users" on-database *users-database*)
      (format t "User with ID of ~A has name ~A.~%" id name))

и это скрывает все содержимое базы данных (транзакции, правильное закрытие соединения, выборку данных и т. Д.), Тогда как в C # это требует создания SqlConnections, SqlCommands, добавления SqlParameters к SqlCommands, зацикливания на SqlDataReaders, правильного их закрытия.

2 голосов
/ 19 мая 2017

Хотя все вышесказанное объясняет, что такое макросы и даже имеют классные примеры, я думаю, что ключевое отличие между макросом и нормальной функцией заключается в том, что LISP сначала оценивает все параметры перед вызовом функции. С макросом все наоборот, LISP передает параметры, не оцененные, в макрос. Например, если вы передадите (+ 1 2) функции, функция получит значение 3. Если вы передадите это макросу, она получит список (+ 1 2). Это можно использовать для создания невероятно полезных вещей.

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

    (defmacro working-timer (b) 
      (let (
            (start (get-universal-time))
            (result (eval b))) ;; not splicing here to keep stuff simple
        ((- (get-universal-time) start))))
    
    (defun my-broken-timer (b)
      (let (
            (start (get-universal-time))
            (result (eval b)))    ;; doesn't even need eval
        ((- (get-universal-time) start))))
    
    (working-timer (sleep 10)) => 10
    
    (broken-timer (sleep 10)) => 0
    
0 голосов
/ 02 апреля 2013

Я получил это из обычной кулинарной книги LISP, но я думаю, что это объяснило, почему макросы LISP хороши в хорошем смысле.

"Макрос - это обычный фрагмент кода на Лиспе, который работает с другим фрагментом предполагаемого кода на Лиспе, переводя его в (исполняемый вариант) исполняемый Лисп. Это может показаться немного сложным, поэтому давайте приведем простой пример. вам нужна версия setq, которая устанавливает две переменные в одно и то же значение, поэтому если вы напишите

(setq2 x y (+ z 3))

, когда z=8 и x, и y установлены на 11. (Я не могу думать об этом, но это просто пример.)

Должно быть очевидно, что мы не можем определить setq2 как функцию. Если x=50 и y=-5, эта функция получит значения 50, -5 и 11; он не знал бы, какие переменные должны быть установлены. Что мы действительно хотим сказать, так это то, что когда вы (система Lisp) видите (setq2 v1 v2 e), относитесь к нему как к (progn (setq v1 e) (setq v2 e)). На самом деле, это не совсем правильно, но пока подойдет. Макрос позволяет нам сделать это точно, указав программу для преобразования входного шаблона (setq2 v1 v2 e) "в выходной шаблон (progn ...)."

Если вы подумали, что это хорошо, вы можете прочитать здесь: http://cl -cookbook.sourceforge.net / macros.html

0 голосов
/ 07 января 2011

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

...