LINUX.ORG.RU

Нужны ли макросы в лиспе?

 


2

2

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

Yes, there is a macro mechanism in PicoLisp, to build and immediately execute a list of expressions. But it is seldom used. Macros are a kludge. Most things where you need macros in other Lisps are directly expressible as functions in PicoLisp, which (as opposed to macros) can be applied, passed around, and debugged. For example, Common Lisp's DO* macro, written as a function:

(de do* "Args"
   (bind (mapcar car (car "Args"))
      (for "A" (car "Args")
         (set (car "A") (eval (cadr "A"))) )
      (until (eval (caadr "Args"))
         (run (cddr "Args"))
         (for "A" (car "Args")
            (and (cddr "A") (set (car "A") (run @))) ) )
      (run (cdadr "Args")) ) )

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

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



Последнее исправление: phill (всего исправлений: 1)
Ответ на: комментарий от phill

Типа того. Если thing — сущность нулевого метауровня, $thing — первого метауровня, $$thing — второго, и т. д., то ничто же формально не запрещает использовать $$$$$stuff в определении stuff напрямую (под честное слово, что её аргументы будут из адекватного метауровня).

ilammy ★★★
()
Последнее исправление: ilammy (всего исправлений: 1)
Ответ на: комментарий от ilammy

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

Макросы ограничивают выразительность языка, чтобы взять на себя ответственность за то, что 1) функции никогда не будут выполнять вычисления над макросущностями, 2) макросы никогда не будут выполнять вычисления над рантайм-значениями. Именно ради того, чтобы вычисления можно было чётко разделить на фазы и выполнить отдельно. By design.

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

Точно так же некоторые другие сообщества решили отдать ещё чуточку своей свободы, чтобы переложить и проверку типов на компилятор. А для братьев Столлмана есть PicoLisp.

ilammy ★★★
()
Ответ на: комментарий от ilammy

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

Только со временем сообщество решило, что ответственность компилятора (читай: оптимизации) несколько важнее собственной свободы самовыражения.

Я бы сказал, что сообщество «грамотно подвели» к этому решению, поскольку, это решение выгодно не сообществу, во всяком случае, не лучшей его части, а скорей, отвечает интересам совместной разработки на благо корпораций (возможно — добра:)). Разделение труда.

А для братьев Столлмана

Хрен знает почему, но столмановский лисп компилируется, несмотря, на dynamic binding. Парадокс. К тому же, он громко гавкает на TCL, который, как раз, интерпретируемый, и вполне себе мощный, помощней сегодняшних лиспов будет, поэтому, про RMS и его братьев не все так очевидно.

phill
() автор топика

про то что пиколисп - говно, уже писали?

lazyklimm ★★★★★
()
Ответ на: комментарий от mix_mix

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

Тень archimag говорит, что в реальности этого никто не делает.

tailgunner ★★★★★
()
Ответ на: комментарий от phill

Нет в макросах никакого волшебства. Возможно, поэтому вы и не понимаете их сути.

elyadow
()
Ответ на: комментарий от tailgunner

«Расширять компилятор» - это, наверное, через compiler-macro, которые могут разворачивать вызов функций в более подходяий вариант при некоторых абстоятельствах. А так, макросы и компиляция - вещи ортогональные

AVC_Verehrer
()

А вот помочь мне в моём треде вам слабо, лишперы

subj

AVC_Verehrer
()
Ответ на: комментарий от tailgunner

А чего ты хочешь-то? Именно каких-то «расширений компилятора»? Тут возможностей не много, на самом деле. Но есть, например, вещи типа cl-simd, которые, таки да, позволяют для того же SBCL генерировать крутой SSE SIMD код.

Да, ваш, archimag, безусловно, знаменитый кодер, но не стоит возводить его в идолы. Я порой какие-то весьма спорные вещи от него почитываю

AVC_Verehrer
()
Ответ на: комментарий от AVC_Verehrer

А чего ты хочешь-то?

Навороченного eDSL.

Именно каких-то «расширений компилятора»?

Нет, но за неимением вышеизложенного тоже подойдет.

archimag, безусловно, знаменитый кодер, но не стоит возводить его в идолы

Я не считаю его знаменитым (что за слово-то в отношении инженера) и тем более не возвожу его в идолы. Но он был действующим программистом на Лисп и варился в его экосистеме. Естественно, что его слова имеют больший вес, чем слова всех анонимных и свежезарегистрированных экспертов.

tailgunner ★★★★★
()
Ответ на: комментарий от elyadow

Ты на протяжении всего треда забиваешь эфир каким то невнятным вяканьем. Есть сомнение, что ты лисп вообще знаешь, и знаешь, что такое макросы. Весь разговор, мля, «они хорошие», «их надо понимать», «вы не понимаете»... Ты бы хоть кусок кода какой привел для приличия, а так, х*ля ты среди мужиков отираешься, под ногами путаешься, не стыдно?

anonymous
()
Ответ на: комментарий от elyadow

А то что?

Ты почему-то решил, что я тебе угрожаю? Это клиника.

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

Мужики, я опять разлогинился. Как объяснить им, что макросы не нужны? Кстати, кто знает, почём можно получить банку спермы саши бургера?

anonymous
()
Ответ на: комментарий от anonymous

Нет, не стыдно. Стыдно как раз предъявлять с победным видом какие-то идиотские куски кода, когда любому, кто имеет понятие о макросах, понятно, что любой код с макросами можно заменить на эквивалентный код без макросов просто раскрыв все макросы. Что эти ваши примеры должны демонстрировать? Может быть, фотография Ника Вуйчича доказывает, что руки-ноги не нужны? Может мне надо объяснить магию рук и ног? Назвать по именам всех, кто постоянно пользуется руками и ногами?

elyadow
()
Ответ на: комментарий от elyadow

Ты че, идиот? Ну ка, изобрази if-then-else «эквивалентным кодом без макросов». Совсем страх потеряла школота.

anonymous
()
Ответ на: комментарий от anonymous

Как ты можешь сделать fexprs на макросах,

написать макрос, define-fexpr, который будет обораичвать все значения в thunks автоматом и подзолять евалить их внутри функции.

Fexpr'ы могут сделать ровно то же самое, что и макры

каким хером, если макросы исполняются в -1 фазе относительно работы кода, где они используются?

которые раскрываются в компилтайме?

да, поэтому fexprы и не заменяют макросов.

Том самом, которого вообще нет в Picolisp?

проблемы убогих реализаций.

x4DA ★★★★★
()

Может быть, их использование — это, всего лишь, дань моде и вынужденный компромисс между выразительностью языка и возможностью компиляции?

Макросы и прочие средства генерации кода — это ВСЕГДА средства борьбы с невыразительностью языка.

Miguel ★★★★★
()
Ответ на: комментарий от elyadow

К тому же, благодаря CLOS. Можно обойтись вообще без if (smalltalk-style, как объяснил yoghurt):

(defgeneric if-fn (bool then else))
(defmethod if-fn (obj then else)
  (declare (ignore obj else))
  then)
(defmethod if-fn ((obj null) then else)
  (declare (ignore obj then))
  else)
* (if-fn (= 7 7) 1 2)

2
* (if-fn (= 7 7) 1 2)

1
* 

// Вася

anonymous
()
Ответ на: комментарий от anonymous
* (if-fn (= 7 6) 1 2)

2

Неудачно закопипастил из слайма

anonymous
()
Ответ на: комментарий от ilammy

Где условие, что он должен быть ленивым?

В sclang then и else обернуты ещё в функции:

(defgeneric if-fn (bool then else))
(defmethod if-fn (obj then else)
  (declare (ignore obj else))
  (funcall then))
(defmethod if-fn ((obj null) then else)
  (declare (ignore obj then))
  (funcall else))

(if-fn (= 4 4) #'(lambda () (print 'a)) #'(lambda () (print 'b)))
AVC_Verehrer
()
Ответ на: комментарий от AVC_Verehrer

А вот ленивости || или && в sclang нет:

(4==4) || ("s".error)

ERROR: s
true

Потому что реализовано всё также через методы класса Boolean

Boolean : Object
&& <Boolean-&&>
and <Boolean-and>
archiveAsCompileString <Boolean-archiveAsCompileString>
asBoolean <Boolean-asBoolean>
asInteger <Boolean-asInteger>
binaryValue <Boolean-binaryValue>
booleanValue <Boolean-booleanValue>
guiClass <Boolean-guiClass>
if <Boolean-if>
keywordWarnings <Boolean-keywordWarnings>
nand <Boolean-nand>
not <Boolean-not>
or <Boolean-or>
printOn <Boolean-printOn> (stream)
storeOn <Boolean-storeOn> (stream)
trace <Boolean-trace>
while <Boolean-while>
xor <Boolean-xor> (bool)
|| <Boolean-||>
Boolean
AVC_Verehrer
()
Ответ на: комментарий от AVC_Verehrer

Только зачем тут CLOS?

(defun if-fn (cond then else)
  (if cond (funcall then) (funcall else)) )
 
(defmacro if! (cond then else)
  `(if-fn ,cond #'(lambda () ,then) #'(lambda () ,else)) )
 
(if! (= 1 2) (print "then") (print "else"))

Или спрятать if под ковёр специализаторов — это типа избавиться от него в определении?

ilammy ★★★
()
Ответ на: комментарий от ilammy

Или спрятать if под ковёр специализаторов — это типа избавиться от него в определении?

Что-то вроде :) Просили без if - получайте :)

AVC_Verehrer
()
Ответ на: комментарий от AVC_Verehrer

А чё с такого как ты взять?

Солнышко, что ж ты такой нервный? Работу найти не можешь?

Pavval ★★★★★
()
Ответ на: комментарий от x4DA

что нет?

По-моему, я пишу вполне по-русски.

бывает, что язык выразителен для всех задач?

А вот это не бывает.

Miguel ★★★★★
()
Ответ на: комментарий от AVC_Verehrer

Где условие, что он должен быть ленивым?

Если if-как-функция, то вообще достаточно and и or с not.

А так if statement/expression везде «ленивый».

quasimoto ★★★★
()
Ответ на: комментарий от AVC_Verehrer

Просили if-без-макросов, вроде.

А and и or - макросы

Которые [могут быть] определены через спец. форму if :)

А если наоборот (с примитивными булевыми операциями), то http://en.wikipedia.org/wiki/Multiplexer#Digital_multiplexers, то есть p && x || !p && y — лисповые and, or и not как раз подходящие:

(define (i p x y) (or (and p (x)) (and (not p) (y))))
(i #t (lambda () 1) (lambda () 2))
; 1
(i #f (lambda () (print 0) 1) (lambda () 2))
; 2

З.Ы. кстати в Scheme/Racket нифига не макросы.

quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 1)
Ответ на: комментарий от quasimoto

кстати в Scheme/Racket нифига не макросы.

Первый раз слышу:) А что там все эти define-syntax и прочее. Их вроде, обычно, называют «гигиенические макросы». А что это тогда, если не макросы?

phill
() автор топика
Ответ на: комментарий от phill

Я про if/and/or/delay и т.п. — по r4rs / docs.racket-lang.org всё это просто syntax. Хотя в r5rs уже есть различие syntax (if) / library syntax (and/or/delay).

quasimoto ★★★★
()

Нужны ли макросы в лиспе?

нужны ли функции в сишечке?

нужны ли метки в ассемблере?

MyTrooName ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.