Объявление шаблона дизайна в макросе в Clojure - PullRequest
2 голосов
/ 09 марта 2011

Одним из достоинств Lisp является макрос. Я много читал, что на Java вы снова и снова пишете шаблоны проектирования. Не в Лиспе / Clojure.
В Lisp / Clojure вы объявляете шаблон в макросе и вам нужно только написать реальный код.

Ладно, красиво и модно, но видеть - значит верить.

Не могли бы вы предоставить мне (или направьте мне) пример с кодом, предпочтительно Clojure, о том, как объявить шаблон проектирования в макросе?

Ответы [ 4 ]

10 голосов
/ 09 марта 2011

Большинство существующих шаблонов проектирования возникли и имеют смысл только в объектно-ориентированном мире.Как только вы вступаете в функциональное программирование и, возможно, особенно в диалекты Лиспа, такие как Clojure, ваша потребность в шаблонах дизайна становится все меньше и меньше.Здесь интересно обсудить шаблоны проектирования и FP здесь .

С другой стороны, макросы не предназначены для инкапсуляции шаблонов проектирования, а скорее расширяют язык с помощью конструкций, которые удобнее решатьпроблема под рукой.Возьмем макрос with-open: называть его шаблоном проектирования для вызова ресурса close кажется просто неправильным.

Шаблоны существуют и в мире FP, но вы этого не делаете.У них больше нет объектов, их основное внимание уделяется алгоритмам.Хорошими примерами «шаблонов» для языков FP являются монады и застежки-молнии .

Предупреждение: может потребоваться время, чтобы разобраться в этих понятиях, но определенно стоит понятьнемного из них.

3 голосов
/ 11 марта 2011

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

; a simple function
(defn square [x] (* x x))

; a macro to "decorate" a function with a debug output println
(defmacro with-debug-output [f] 
  `(fn [& args#] 
     (let [result# (apply ~f args#)]
       (println (str "Debug-output: " result#))
       result#)))


; call the straight function
(square 16)
=> 256

; call the decorated function
((with-debug-output square) 16)
Debug-output: 256
=> 256

Примечание. Для этого макрос не нуженВы также можете сделать это с помощью функции более высокого порядка.

1 голос
/ 09 марта 2011

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

Возьмите шаблон стратегии.Если в вашем языке есть лямбда-выражения, он вам больше не нужен.

Часто вы можете использовать один и тот же шаблон, но ваш язык упрощает его выражение, так что вы никогда не назовете его Реализация шаблона проектирования.Это просто программирование.

0 голосов
/ 06 сентября 2011

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

Например, посмотрите на макрос if-not изClojure ядро.Это похоже на стандартное «если», но инвертировано: если условие ложно, выполняется первый бит кода;если условие истинно, выполняется второе.

Если вы напишите что-то похожее как функцию, оно не будет работать.Версия функции будет выполнять код «then» и «else» сразу после вызова функции, независимо от того, является ли условие истинным или ложным.Макро-версия, с другой стороны, может выбирать, запускать ли (и когда) код, указанный в качестве аргументов.

Менее тривиальным примером является абстрагирование типичного "try ... catch".... наконец, управляющая конструкция вездесущая в Java и распространенная в других языках в макрос «с чем угодно».Если вы держите конечный ресурс, такой как дескриптор файла или сетевой сокет, который должен быть освобожден, даже в случае ошибки вам необходим блок "finally", чтобы сделать это, но код вашего приложения должен быть вставлен без оценки ввнутренняя часть блока "try", который будет запущен в этом контексте.

Вы копируете по существу одну и ту же неизменную шаблонную строку try ... catch ... finally везде в вашей программе и вставляете небольшой локальный фрагментприменимый раздел в части "попробовать".(Посмотрите на любой нетривиальный исходный код Java.) Этот шаблон не может быть абстрагирован в функцию, потому что функция будет оценивать локальный код сразу при вызове в контексте вызывающего, а затем выдавать результат этого кода в функцию «с чем угодно».

С другой стороны, макрос может задерживать оценку до тех пор, пока он не будет специально вызван кодом макроса, что позволяет ему разделить ваш произвольный локальный код наИнтерьер конструкции «попробуй» неоценен.Весь результат (весь try / catch / finally, включая ваш неоцененный специфичный для приложения код в попытке) затем возвращается вызывающей стороне и вставляется в контекст вызывающей стороны, завершается, чтобы быть там выполненным.

Таким образом, вы можете написать программу, которая пишет программы.

...