LINUX.ORG.RU

[Lisp] туплю с defmacro

 


0

2

Есть код:


(defun get-action-name (list)
	(mapcar #'(lambda (def-list) (list (first def-list) (second def-list))) list))

(defmacro with-new-actions (parent actions-list
							&body body)
  (get-action-name actions-list))

(defparameter *workspace-actions-list* 
  '((aNew "&New" #'new-page-handler "tab- new" "Ctrl+N")
	(aOpen "&Open" #'open-page-handler "open" "Ctrl+O")))

(with-new-actions 'parent *workspace-actions-list*) ;; 1

(with-new-actions 'parent ((aNew "&New" #'new-page-handler "tab- new" "Ctrl+N")
	(aOpen "&Open" #'open-page-handler "open" "Ctrl+O"))) ;; 2

Проблема в том что строка (2) раскрывается, а строка (1) - нет.

Вопрос как раскрыть *workspace-actions-list* внутри defmacro ? Google молчит, вот туплю и мучаюсь.

★★★
Ответ на: комментарий от yyk

автором предполагалось, что пользоваться его макросами будут адекватные люди, прочитавшие документацию

1. ты в документации собрался использовать все поюзаные формы? 2. Замечательно - то есть либо я использую нужные макросы, либо переопределяю let. Спасибо, но мне удобнее сделать и то и то одновременно.

В том-то и дело, что да. А ты продолжаешь демонстрировать полное незнание CL. Что-то меня задалбывает рассказывать тебе, что ты нихера не знаешь...

От того, что ты хоть тысячу раз скажешь, что что-то можно, это что-то возможным не станет. Иными словами, без пруфов ты - х*й простой.

...и если я захочу пользоваться _только_ модифицированными формами, код превратиться в говно!

нет, оно работает на весь синтаксический объект. Ну чтоб тебе было понятно - представь себе, что (local-syntax-introduce ...) - это (quasyquote ...), при чем (local-syntax-introduce (local-syntax-introduce x)) = x, то есть он сам себя отменяет. Другими словами, чтобы сделать, как ты хочешь, надо просто на каждую «`» или «'» иди "," навесить по этой ф-и, но проще воспользоваться уже готовым defmacro, раз уж тебе понадобилась такая форма. Он именно так и реализован.

Ты о "дефолтном" импорте стандартных пакаджей и "почти запрете" на их переопределение? Это скорее мера предупреждения для таких дебилов как ты.

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

это твоё сраное ИМХО

То, что можно насрать в другой пекедж - это факт, а не ИМХО. Вот плохо это или хорошо - уже вопрос ИМХО, да.

Воспроизвести тот твой пример точь в точь на CL - ровно столько-же кода.

Он невоспроизводим точь в точь на CL. Вон, один товарищ уже пытался воспроизводить.

а для CL - SBCL по твоей дебильной логике?

Надо, наверное, понимать контекст, нет? Racket гораздо больше добавляет в Scheme, чем SBCL в CL, это во-первых. Во-вторых, Racket вообще официально уже не Scheme. Да, в racket можно запускать схемопрограммы, но и все. На этом совместимость заканчивается.

да, с тем лишь исключением, что они мне понятны.

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

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

den73, нет, прям так как в CL нельзя, скомпилированный «дистрибутив» программы не включает в себя весь рантайм, функции eval/load/compile/etc, Racket не поддерживает инкрементальную компиляцию.

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

den73, нет, прям так как в CL нельзя, скомпилированный «дистрибутив» программы не включает в себя весь рантайм, функции eval/load/compile/etc, Racket не поддерживает инкрементальную компиляцию.

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

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

>1. ты в документации собрался использовать все поюзаные формы? 2. Замечательно - то есть либо я использую нужные макросы, либо переопределяю let. Спасибо, но мне удобнее сделать и то и то одновременно.

я всего-навсего говорил, что переопределяя стандартные формы (т.е. именно cl::<name>) или «затеняя их» ты должен понимать что же ты делаешь и какие могут быть последствия. Извращенцы, желающие «два в одном» идут лесом...

От того, что ты хоть тысячу раз скажешь, что что-то можно, это что-то возможным не станет. Иными словами, без пруфов ты - х*й простой.


От того, что ты хоть тысячу раз скажешь, что что-то невозможно, это что-то невозможным не станет. Иными словами... =]]]

нет, оно работает на весь синтаксический объект.


да, ибо этих объектов (различных) по три на каждую строчку кода

Вот плохо это или хорошо - уже вопрос ИМХО, да.


О, проблески сознания! (радуюсь как ребёнок...)

Он невоспроизводим точь в точь на CL.


«От того, что ты хоть тысячу раз скажешь, что что-то невозможно...» =)

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


А у тебя очень опасная привычка на основании твоих собственных домыслов о недосказанном или криво изложенном делать однозначные и категоричные выводы. Для тебя опасная...

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

[quote] Не понял, «не нужны» в смысле «есть другой путь» или это - идеологема? У меня половина макросов на лиспе с keyword аргументами. [/quote] Там паттерн-матчинг применяется. Например, нам надо сделать let-подобный макрос, будет выглядеть так: [code] ((define-syntax-rule (my-let ([name expr] ...) body ...) *код макроса*) [code] Кейворд аргументы использовать нельзя, дело в том, что макрос принимает один единственный аргумент. Всегда. Этот аргумент - это синтаксический объект формы вызова. Например, мы вызываем макрос (yoba x y), тогда аргумент, который будет передан в макрос yoba, это вся форма - собственно #'(yoba x y). Можно работать с этим объектом в макросе напрямую, а можно использовать запиленные в стандарте формы, которые этот объект сразу автоматом парсят, в соответствии с теми или иными паттернами. В паттернах кейворды использовать можно. Кроме syntax-rules и syntax-case есть еще syntax-parse - там, фактически, можно описать целую грамматику в терминах синтаксических классов.

[code] В лиспе, когда я вижу в теле функции ошибку, я иду в исходник, меняю это тело и нажимаю C-c C-c. После этого (не перезагружая программы) у меня уже новая функция (если не особо жёстко работает оптимизатор). [/code] Если ты говоришь о репле - то все нормально, там можно обычным образом писать дефайн несколько раз и все работает, я имел в виду вариант, когда ты решил скомпилировать файл. [code] Добро пожаловать в DrRacket, версия 5.0.2 [3m]. Язык: racket [выбранный].

(define (yoba x y) (/ x y))
(yoba 2 0)

. . /: division by zero

(define (yoba x) (add1 x))
(yoba 1)

2 [/code] То есть если ты все скидываешь в репл, то будет ок.

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

Если ты говоришь о репле - то все нормально, там можно обычным

образом писать дефайн несколько раз и все работает, я имел в виду

вариант, когда ты решил скомпилировать файл.


Я говорю вот о чём:
загрузить лисп
редактировать файл a.lisp в редакторе

load (compile-file a.lisp)

;;; содержимое файла a.lisp с функцией yoba.

'yoba ; и нажимаем M-.

открывается окно редактора с файлом a.lisp в том месте, где определан функция yoba. Меняем определение функцию yoba. C-M-c
IDE разработчика вызывает:
(compile (defun yoba #| новое определение |#))
результат:
весь файл a.lisp скомпилирован, функция yoba тоже скомпилирована, при этом я всё ещё нахожусь в REPL. Описанное - это основной «внутренний цикл» разработки в CL. Иногда от него бывают отступления, но не так уж и часто. Например, вместо компиляции одной функции иногда надо перекомпилировать весь a.lisp, или всё, что от него зависит. Некоторые не знают этот сценарий по безграмотности (и я тоже не сразу разобрался). Но вообще-то, тот, кто его не знает, тот не может считаться знающим CL. Ты, кстати, не ответил на вопрос о твоём опыте работы с CL.

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

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

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

[quote] я всего-навсего говорил, что переопределяя стандартные формы (т.е. именно cl::<name>) или «затеняя их» ты должен понимать что же ты делаешь и какие могут быть последствия. Извращенцы, желающие «два в одном» идут лесом... [/quote] Если макросистема говно - то последствия могут быть плохими. Если макросистема нормальная - никаких плохих последствий нет. Но, конечно же, чего в CK нельзя, то сразу объявляется ненужным.

[quote] От того, что ты хоть тысячу раз скажешь, что что-то невозможно, это что-то невозможным не станет. Иными словами... =]]] [/quote] Кода от тебя нету? Нету. Так и запишем: «трепло».

[quote] да, ибо этих объектов (различных) по три на каждую строчку кода [/quote] объект один. Вообще один, на весь макрос. Я же тебе вполне понятно объяснил - оно так же как «`» работает.

[quote] А у тебя очень опасная привычка на основании твоих собственных домыслов о недосказанном или криво изложенном делать однозначные и категоричные выводы. Для тебя опасная... [/quote] не вижу ничего опасного в том, чтобы изложить факты.

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

> Смотри, у меня есть некий набор макросов. Их не я написал, но я их использую в своем проекте. И тут я захотел у себя, в своем проекте поменять let. Ну удобно мне в силу каких-то причин, чтобы let работал не по стандарту, а как-то иначе. И ВНЕЗАПНО после этого переопределения все макросы перестают работать. Почему? Потому что в них есть let. И автором макросов предполагалось, что let работает строго определенным образом. Это дикость. Нормальная ситуация - это когда я переопределяю let, а макросы продолжают работать, как работали.

Там выше уже сказали, что let --- это спецформа, но, я думаю, пойнт анонимуса будет соблюден если мы возьмём какой-нибудь произвольный макрос, пусть даже не из защищённого пакета cl, например, metabang-bind:bind, который выполняет почти те же функции, что и let. Итак, идея в том, что если мы переопределим bind, то все макросы, в которые входит bind, перестанут корректно работать. Внимание, вопрос: с какой ещё целью кроме как изменение работы имеющихся макросов нужно переопределять bind?

При этом в соответствии с отквоченным я хочу подчеркнуть, что проект отдельный и с bind никак не связан. Это значит, что в нём используются свои пакеты, а bind максимум импортируется из пакета metabang-bind для удобства. В таком случае можно воспользоваться shadow и создать свой bind с блэкджеком и дамами, фактически не изменяя metabang-bind:bind и, соответственно, не затрагивая работу определённых ранее (в других пакетах) макросов.

Что же касается макросов, определённых в этом пакете --- это же относится и к случаю когда мы разрабатыаем этот metabang-bind:bind и работаем в пакете metabang-bind, --- то да, такое изменение отразится на их работе. Однако эта проблема имеет какое-то значение только при интерактивной разработке с реплом; если такое двойное определение встречается в коде, то это либо грубая ошибка эквивалентная переопределению функции, либо тонкое извращение, и в этом случае автор должен знать, что он делает.

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

> Уже давно мечтаю такую написать.
Вот и напиши :-)

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

анафорический if

Я бы всё-таки хотел узнать, чем это отличается от

(defmacro aif (test then else)
  `(let ((it ,test))
     (if it ,then ,else)))

Я вижу одну проблему, связанную с необходимостью экспорта-импорта it в другие пакеты, если этот aif там используется, но это небольшая плата, которую я готов заплатить за простоту макроса по сравнению с тем, что написано выше. Ещё что-нибудь?

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

> Внимание, вопрос: с какой ещё целью кроме как изменение работы

имеющихся макросов нужно переопределять bind?


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

Вот в момент разработки, во время экспериментов с REPL, ситуация с двойным определением может возникнуть. Но, как уже выяснили, Racket не предлагает решение данной проблемы, ибо вообще не поддерживает необходимый стиль разработки. «если у вас нету дома, пожары ему не страшны» (с)

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

IDE разработчика вызывает: (compile (defun yoba #| новое определение |#))

если эта команда вызвана в репле, так же как и

load (compile-file a.lisp)

;;; содержимое файла a.lisp с функцией yoba.

'yoba ; и нажимаем M-.

то все так и есть

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

[quote] с какой ещё целью кроме как изменение работы имеющихся макросов нужно переопределять bind? [/quote] Случайно вышло. Баг такой.

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

> Те люди, которые всегда ждут перекомпиляцию и перезапуск программы после изменения одной строчки - их много.

то есть риска остаться с образом системы и кодом который не ботстрапится в рабочую систему нет?

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

Почему же нельзя? Можно. Баг на то и баг.

Если речь о CL то никак не получится написать макрос bind, перопределяющий исходный, «случайно».

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

> то есть риска остаться с образом системы и кодом который

не ботстрапится в рабочую систему нет?


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

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

> то есть риска остаться с образом системы и кодом который не ботстрапится в рабочую систему нет?
Первый мой ответ был неправильным. В первом приближении - риска нет. Во втором - он есть, поскольку есть ещё порядок загрузки. Любое определение зависит от контекста, в котором оно выполнено. Если контекст в момент переопределения отличается от того, в котором было произведено первое определение, то мы получим как бы систему, соответствующий ей исходник, но мы не загрузимся в такую же систему с чистого листа. Такое случается редко и именно это я имел в виду в первом сообщении.

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

>Но, конечно же, чего в CK нельзя, то сразу объявляется ненужным.

Дооо, а ежели что-то есть в схеме, то без этого - «ни жисть», я уже понял

Кода от тебя нету? Нету.


И не будет. А то опять начнутся отмазки «это не гигиена, это скоуп». И я даром не учу =)

объект один. Вообще один, на весь макрос.


А ежели надо чередовать local-introduce с global-introduce? gensym раем покажется...

не вижу ничего опасного в том, чтобы изложить факты.


Я тебе уже говорил: не льсти себе, подойди ближе

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

А ежели надо чередовать local-introduce с global-introduce? gensym раем покажется...

Генсим не может раем показаться, потому что если угодно ее можно использовать в let-форме так же, как gensym. В любом случае сферический пример с чередованием такой сферический. На практике в 90% макросов вообще не нужно обходить гигиену, в 90% из оставшихся 10% дело обходится парой (local-introduce ...). Пример, в котором придется их чередовать, я даже затрудняюсь представить (если это только не макрос-однострочник с 3 идентификаторами, из которых второй - без гигиены, огда да, жууууткое чередование выходит.).

И не будет.

Так и запишем - как сделать, не знаешь.

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

>Так и запишем - как сделать, не знаешь.

та на заборе много чего написано... пиши-пиши...

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

Если речь о CL то никак не получится написать макрос bind, перопределяющий исходный, «случайно».

Думаю, можно. Следите за руками:

(defpackage "TEST")
(defmacro test::test () 42)
(export 'test::test "TEST")
(import 'test:test)
(test) ; => 42
(defmacro m () `(test))
(flet ((test () 11)) (m)) ; => 11
(defmacro test () 54)
(test::test) ; => 54

Не знаю насколько это «случайно», но подобные вещи --- одна из причин, почему я стараюсь не увлекаться import и use-package.

; CL-анонимус

P.S. Хм, эта конструкция с flet заставляет задуматься...

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

> Вобщем-то понятно, почему общелисперы так упираются в свои общемакросы - принципы работы любой чуть более сложной макросистемы для них недосягаемы, даже если объяснять на пальцах, как пятилетним.

будешь смеяться, но общелисперам даже своя собственная макросистема не понятна. вот swizard вроде бы написал неплохую оптимизацию трёхэтажным макропрограммированием. как написал? как додумался до такого? сначала он в бложике пишет, что тупо на ощупь в SLIME подобрал macroexpand. потом, вроде бы появился метод, цель и замысел (ну или ощущение понимания, хотя бы).
факт: этот код распарсить сложно, его только подобрать можно в REPL. то есть, это write-only код, его можно только написать — распарсить написанное не могут.

ок, со схемой и гигиеной вроде бы понятно — лучшая модульность, код как модуль, включая макросы.
а когда могут быть полезны AST-макросы? то есть, когда манипуляции AST деревом (вроде того, как сделаны макросы в Nemerle, Nimrod и Dylan) могут быть сильно мощнее простых макросов?
вот эти syntax-rule и синтаксические объекты в схеме это что, AST?

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

> Макросы схемы, кстати, ещё не предел --- на дальнем конце шкалы маячит Template Haskell, который за тебя ещё и типы используемых переменных проверит.

а в каком-нибудь typed racket не проверит? то есть, макросы схемы — это что, просто кусок кода, кусок произвольного AST, кусок правильного AST с проверкой типов?
то есть, если указать что макрос принимает только целые, и подставить строку, что будет?

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

У вас фундаментальные проблемы с понимание что такое макросы в лиспе.

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

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

опять не понятно. Ну доопределим макрос над let, defun такой, чтобы а)отрабатывал, создавая символ б)ложил в стек-plist привязанный к этому символу его охватывающую область видимости (для toplevel формы — пакет, для 1 уровня — символ, связанный с этой toplevel формой, для 2 уровня — 1 уровень).
Чего не хватает в такой схеме для полной аналогии с гигиеничными макросами (за исключением того, что такие списки, привязанные к символам не обеспечат нормальной производительности)?

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

Например, есть ли аналог in-package, чтобы я мог попасть в контекст того модуля, где эта функция была определена? Ведь она может ссылаться на какие-то частные функции и переменные этого модуля. Если я в REPL нахожусь в другом пр-ве имён, то толку от перекомпиляции никакого не будет.

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

> Тогда дальше не интересно.

ты так говоришь, как будто языков с инкрементальной компиляцией пруд пруди =)

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

> ты так говоришь, как будто языков с инкрементальной компиляцией

пруд пруди =)


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

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

> Racket не поддерживает инкрементальную компиляцию.

а что с теми реализациями схемы, у которых есть swank-бекенд к SLIME? оно работает?

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

странная точка зрения. Как будто, ты не знаешь, как эту инкрементальную компиляцию можно сделать.
Другое дело, что подкрепляться это должно в самом рантайме языка, его фичами. Вот можно сделать инкрементальную конпеляцию в С++ — и что? поймали исключение, выбросили, размотали стек, аборт. Без условий и рестартов неинтересно.
Есть рестарты, нет hot update кода. Опять-таки не интересно, если во время загрузки обновлённого «плагина» приложение может упасть. Вот если принципиально не может...

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

Это опять-таки реализация Racket. В некоторых других вроде есть SLIME backend, он же по идее как-то работает.

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

> Это опять-таки реализация Racket. В некоторых других вроде есть SLIME backend, он же по идее как-то работает.
Уверенного «можно» я не слышу.

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

> Как будто, ты не знаешь, как эту инкрементальную компиляцию

можно сделать.


Нет, не знаю. Во всяком случае, в удобном для процесса разработки варианте.

Вот можно сделать инкрементальную конпеляцию в С++


Нельзя. Лишь подмена кода конкретных функций.

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

> дело в том, что макрос принимает один единственный аргумент. Всегда. Этот аргумент - это синтаксический объект формы вызова. Например, мы вызываем макрос (yoba x y), тогда аргумент, который будет передан в макрос yoba, это вся форма - собственно #'(yoba x y). Можно работать с этим объектом в макросе напрямую, а можно использовать запиленные в стандарте формы, которые этот объект сразу автоматом парсят, в соответствии с теми или иными паттернами. В паттернах кейворды использовать можно. Кроме syntax-rules и syntax-case есть еще syntax-parse - там, фактически, можно описать целую грамматику в терминах синтаксических классов.

вот про грамматику и синтаксические классы не понятно. Можно так распарсить, чтобы int попадал в один класс, double в другой, string в третий,... class object — в четвёртый, class subobject: object — в пятый?
Чем такое распарсивание отличается от «типизированных макросов»?
Или, можно указать макросу — тут принимаем только константы, тут выражения, тут функцию?

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

>> Вот можно сделать инкрементальную конпеляцию в С++

Нельзя. Лишь подмена кода конкретных функций.


авторы инкрементальных линкеров смотрят на тебя с непониманием.

А даже если и подмену — какая польза если сигнатура меняется неконтролируемо, ломая остальной код? вот если он гарантированно не ломается (из-за той же сигнатуры или ещё из-за чего...)

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

> Уверенного «можно» я не слышу.

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

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

Ну, есть ещё один язык, где ответ положительный и где этим много . Это - SQL (alter table, alter procedure). Ораклом я пользовался давно и мало, не помню. MS SQL безупречен, Firebird - на три с плюсом (нельзя перекомпилировать процедуру, на к-рую есть ссылки, изменения становятся видны другим пользователям после переконнекта). С другими серверами не работал.

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

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

> А даже если и подмену — какая польза если сигнатура меняется неконтролируемо, ломая остальной код?
Это можно сделать безопасно, правда, ценой снижения производительности.

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

Вы тут определённо сами определяете два макроса test - так что вполне осознано.

Once the symbols have been imported, they may be referenced in the importing package without the use of a package prefix when using the Lisp reader.

к примеру, если вы из пакета FOO импортируете переменную *BAR* и измените её с помощью setf - изменится FOO:*BAR*, верно? Это естесвенно. Также и с другими символами (вот макрос в вашем примере).

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

> какая польза если сигнатура меняется

неконтролируемо, ломая остальной код?


В CL это не проблема. Не проблема то, что программа становится некорректной в режиме разработки. А в С++ это проблема, ибо программа просто грохнется.

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

В CL можно изменить определение класса, а в С++ это совершенно немыслимо. Ну да много чего.

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

> Придётся уделить время защите пакетов от тех дыр, к-рые были озвучены в теме. Уже давно задумывал это сделать, пора бы уже сделать.

Ты так говоришь, как будто у тебя есть собственный, уже почти законченный компилятор. Кстати, никто не в курсе, не планируется ли обновление стандарта CL в обозримом будущем?

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

будешь смеяться, но общелисперам даже своя собственная макросистема не понятна. вот swizard вроде бы написал неплохую оптимизацию трёхэтажным макропрограммированием. как написал? как додумался до такого? сначала он в бложике пишет, что тупо на ощупь в SLIME подобрал macroexpand. потом, вроде бы появился метод, цель и замысел (ну или ощущение понимания, хотя бы).

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

вот эти syntax-rule и синтаксические объекты в схеме это что, AST?

Нет. Грубо говоря, синтаксический объект - это структура, которая содержит символ, биндинги символа, информацию о локации, историю экспанда, syntax marks (это штука через которую реализуется гигиена). Ну либо если не символ, то список символов (то есть весь s-expr это синтаксический объект, его можно разбить на список синтаксических объектов и т.д.)

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

Да, но посмотри на flet-форму. Казалось бы локальное определение, но оно неочевидным образом влияет на раскрытие макроса. Почему так происходит понятно, просто раньше я не задумывался над тем, что может быть нехорошо использовать связанные глобальные символы для локальных определений... хотя и не могу вспомнить чтобы я так делал.

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

Например, возьмем теже бекквоты

Синтаксис backquote не связаны с макросами, хотя и часто используется в них. Т.е. претензии к данному механизму в контексте обсуждения макросистемы безосновательным, ибо это просто не часть макросистемы.

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