LINUX.ORG.RU

Вышел Racket 6.4

 ,


4

3

Вышла версия 6.4 языка Racket — языка программирования общего назначения из семейства Lisp/Scheme.

  • Исправлена уязвимость в Web-сервере. Данная уязвимость позволяла получить доступ к любому файлу, доступному Web-серверу для чтения (подробности).
  • Новый инкрементальный сборщик мусора уменьшил паузы, что особенно важно в играх и анимациях.
  • Скроллинг в DrRacket стал быстрее.
  • Добавлен болгарский перевод в DrRacket.
  • Каталог пакетов теперь имеет адрес HTTPS по умолчанию, а не HTTP.
  • Документация теперь может определять свои собственные категории для главной страницы руководства с использованием строк.
  • Шпаргалка по Racket включена в основной дистрибутив.
  • Контракт, который Typed Racket генерирует для типа Any, стал более либеральным, что позволяет большему числу программ как с использованием системы типов, так и без неё работать без ошибок контракта.
  • Redex поддерживает спецификацию связей (binding specifications).
  • Все функции pict принимают pict-convertible, что обеспечивает прозрачное взаимодействие между pict и библиотеками типа 2htdp/image.
  • Команды raco profile и raco contract-profile предоставляют лёгкий доступ к инструментарию профилирования без необходимости изменять сами программы.

>>> Подробности

anonymous

Проверено: maxcom ()
Последнее исправление: Wizard_ (всего исправлений: 6)

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

Спасибо тебе, добрый человек :-) Оставайся всегда таким, каким ты есть - почёт тебе и уважуха от души :-)

anonymous
()

у drracket в данной версии, вроде какие-то проблемы с учётом памяти, мой старый скрипт-генератор-картинок его просто вешает, запускаю через emacs racket-mode, смотрю расход памяти - всё нормально, и отрабатывает так как в предыдущих версиях (6.1 - 6.3, и с drracket всё было в порядке), всё, правда, на второй малине

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

Ну короче я опять немного потыкал макросы сабжа. Выходит довольно мудреный код, потому что мне приходится из макроса вызывать функцию, которая заворачивает синтакс в структуру. Благополучно починил веселый баг «no #%datum syntax transformer is bound», догадавшись, что просто забываю прописать синтаксу биндингс, когда собираю его с помощью (datum->syntax #f <tratata>). Никогда раньше не задумывался о том, что синтакс это не только номер строки, а еще и биндинг. Скотина ракет не говорит ничего о том, что тут зашит какой-то биндинг, когда смотришь на синтакс в репле. Ну и выходят довольно интересные пляски, когда тебе надо и выполнять некие вычисления в компилтайме и использовать удобство шаблонов. Собственно вопрос на засыпку: как кошерно запустить на выполнение в компилтайме шаблон, собранный с помощью syntax-case. Упрощенный пример для мотивации:

#lang racket
(define-syntax (lt stx)
  (syntax-case stx ()
    [(_ ([var expr] ...) body)
     (datum->syntax stx
                    (eval #`(let ([var expr] ...)
                              #,(let ([t (if (symbol? (syntax-e #'body))
                                             (assoc #'body
                                                    (map syntax-e (syntax->list #'([var . expr] ...)))
                                                    free-identifier=?)
                                             #f)])
                                  (if t (cdr t) (car (syntax-e #'(var ...)))))))
                    stx)]))

> (lt ([a 1][x 2]) a)
1
> (lt ([a 1][x 2]) x)
2
> (lt ([a 1][x 2]) 5)
1

Мда, такой простой демо функционал и час плясок с бубном чтоб его поднять....

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

Я бы написал так:

#lang racket
(require (for-syntax syntax/stx))

(define-for-syntax (stx-eval stx expr)
  (datum->syntax stx (eval expr) stx))

(define-syntax (lt stx)
  (syntax-case stx ()
    [(_ ([var expr] ...) body)
     (stx-eval stx #`(let ([var expr] ...)
                       #,(cond
                           [(and (identifier? #'body)
                                 (assoc #'body
                                        (stx-map syntax-e #'([var . expr] ...))
                                        free-identifier=?)) => cdr]
                           [else (stx-car #'(var ...))])))]))

Вообще eval достаточно редко требуется

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

По человечески такая функция пишется так:

(define-syntax (lt stx)
  (syntax-case stx ()
    [(_ ([var expr] ...) body)
     (cond
       [(and (identifier? #'body)
             (assoc #'body
                    (stx-map syntax-e #'([var . expr] ...))
                    free-identifier=?)) => cdr]
       [else (stx-car #'(expr ...))])]))

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

Ну я цикл for делаю на самом деле. Который запускает счетчики в компилтайме и инлайнит свое body на каждую итерацию. Так что в моем случае упрощение не канает. Просто не хотелось мучатся с такой сложнотой не зная правильного пути. Eval, как показал опыт никак не дает собрать внутри себя синтакс. Конечно можно было обойтись без syntax-case, но тогда много писанины было бы с проверками валидности применения макроса и прочим.

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

Виноват, syntax-case тут ни при чем. Вобщем как внутри stx-eval создать синтакс, который вернется наружу не выполнившись?

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

Eval, как показал опыт никак не дает собрать внутри себя синтакс.

Не понял утверждения. Вроде как ты как раз собрал синтакс внутри евала.

без syntax-case, но тогда много писанины было бы с проверками валидности применения макроса и прочим.

Используй syntax/parse

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

Вобщем как внутри stx-eval создать синтакс, который вернется наружу не выполнившись?

Вообще не понял, что ты хочешь. Вот твой пример (stx-eval stx #`(let ...)). Что должно вернуться?

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

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

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

(eval '(let ([x (datum->syntax stx 1)]) x))

Вернёт (datum->syntax stx 1) в пустом пространстве имён. То есть ошибку. Если что-то надо передать в eval, делай так: ((eval '(lambda (stx) (let ([x (datum->syntax stx 1)]) x))) stx)

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

Возвращает 1. Или что ты от него хотел?

А надо #'1

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

((eval '(lambda (stx) (let ([x (datum->syntax stx 1)]) x))) stx)

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

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

Ну придумали бы хотябы спец макрос для такого.

Так он пишется в 3 строки:

(define-syntax lexical-eval
  (syntax-rules ()
    [(_ cmd) (eval cmd)]
    [(lexical-eval cmd var ...) ((eval `(lambda (var ...) ,cmd)) var ...)]))

(let ([a 1]) (lexical-eval '(+ a 1) a)) ; => 2

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

Да мне бы чтоб вообще инфраструктура была готовая. Захотел - евалишь в чистом поле. Захотел - врубил пару пространств имен. Потому что чаще всего смысл запуска евала именно в том чтоб что-то обработать из того пространства, что есть в вызывающем контексте. И кстати

> (eval #'(datum->syntax #f 1))
.#<syntax 1>
то у меня просто где-то в другом месте была лажа.

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

Да мне бы чтоб вообще инфраструктура была готовая. Захотел - евалишь в чистом поле. Захотел - врубил пару пространств имен.

Всё так и есть.

Потому что чаще всего смысл запуска евала именно в том чтоб что-то обработать из того пространства, что есть в вызывающем контексте.

Лексический контекст так не работает, потому что при компиляции имена удаляются. (let ([x 1]) (f x)) и (f 1) — это один и тот же код. А если просто пространство модуля, так define-namespace-anchor и прочие функции про namespace.

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

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

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

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

Так сам же писал "чтоб вообще инфраструктура была готовая". Совсем ненужных функций я там не видел. Есть для использования при довольно экзотичных стилях программирования, так твой пример с eval внутри преобразователя синтаксиса тоже экзотика.

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

Почему expand/step дает только один раз нажать next и в нем нихрена не ясно откуда что взялось, а expand/step-text строчит целую войну и мир раскрытия всяких #%app. Где тут нормальный macroexpand-1? А то я написал одно, а выдает совсем другое. И совершенно не ясно в чем баг.

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

Где тут нормальный macroexpand-1

expand-once

Почему expand/step дает только один раз нажать next и в нем нихрена не ясно откуда что взялось

Он даёт нажать сколько угодно пока есть что раскрывать, но не раскрывая макросы стандартной библиотеки (внизу Macros hiding — можно настраивать).

Для expand/step-text что раскрывать определяется вторым параметром.

А то я написал одно, а выдает совсем другое

Может ссылку дашь? Посмотрю, что не так.

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

Мне дико не хочется втягивать такого хорошего человека в свои кододебри, но текущая попытка отличается простотой, да и код я подчистил как мог. В общем для работы демки надо поставить raco pkg install portaudio. Короче это язык описания синтезатора звука. В планах сделать генерацию C кода, но пока ракет макросами генерю. http://pasterack.org/pastes/79394 - смотреть тут. Внизу закоментированы 2 примера генерации звука, которые в теории должны звучать одинаково. Идея была в том, чтоб в (play (repl ([i (in-range 2)]) (saw (* (+ i 1) 400))) 3) сначала запустился макрос repl и сгенерировал (play (vector (saw (* (+ 0 1) 400)) (saw (* (+ 1 1) 400))) 3), ну а дальше по алгоритму обработки. Но что-то пошло не так. Мне кажется, что я в принципе неправильно написал repl, поскольку писал я его наугад совершенно не представляя, что же на самом деле происходит во всех этих #'#', но в примитивных тестах он работает норм. Я конечно дико извиняюсь.

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

Идея была в том, чтоб в (play (repl ([i (in-range 2)]) (saw (* (+ i 1) 400))) 3) сначала запустился макрос repl и сгенерировал (play (vector (saw (* (+ 0 1) 400)) (saw (* (+ 1 1) 400))) 3)

Вот здесь некорректная постановка задачи. В (repl ([i (in-range 2)]) (saw (* (+ i 1) 400))) у тебя i подразумевается из фазы 1 (компиляции), а saw — из фазы выполнения. Но это нигде явно не указано. Вот что должен вернуть repl для

(repl ([i (in-range 2)]) 
  (let ([i 2])
    (saw (* (+ i 1) 400))))
?

Если нужно решение задачи «создавать вектор при компиляции» и допустимо слегка изменить синтаксис, то можно сделать так:

(define-syntax (repl stx)
  (syntax-case stx ()
    [(_ ([id sequence-expr] ...) body)     
     #`(vector #,@(syntax-local-eval
                   #'(for/list ([id sequence-expr] ...)
                       (quasisyntax body))))]))

> (syntax->datum (expand-once '(repl ([i (in-range 2)]) (saw (* (+ #,i 1) 400)))))
'(vector (saw (* (+ 0 1) 400)) (saw (* (+ 1 1) 400)))

Можно даже
> (syntax->datum (expand-once '(repl ([i (in-range 2)]) (saw #,(* (+ i 1) 400)))))
'(vector (saw 400) (saw 800))
monk ★★★★★
()
Ответ на: комментарий от monk

допустимо слегка изменить синтаксис

Ну в идеале неплохо бы сделать такой repl, который сам решает какой из 3 сценариев выбрать:

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

Но никто мне не мешает сделать разделение явным, с использованием разного синтаксиса. Просто это какбы plain syntax transformer, в то время как тут вполне применим define-syntax-rule без единой #,.

PS. Так что баг произошел из-за захвата переменной i в макросе play? А где тогда хваленая уберзащищенность ракета, которая должна не позволять заколизить переменную без явного указания кодера? Или я просто сбился с racket-way и следует это как-то запилить без eval?

PS2. И это, спасибо

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

в идеале неплохо бы сделать такой repl, который сам решает какой из 3 сценариев выбрать

Если сможешь описать однозначный алгоритм, то можно. «Сам решает» — это искусственный интеллект?

Но никто мне не мешает сделать разделение явным, с использованием разного синтаксиса. Просто это какбы plain syntax transformer, в то время как тут вполне применим define-syntax-rule без единой #,.

Так я же тебе предложил синтаксис: i = runtime, #,i — compile-time. define-syntax-rule можно сделать только если алгоритм выражается в виде подстановок шаблонов, а не явного выполнения кода (у тебя for/list с произвольными параметрами в compile-time).

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

Или я просто сбился с racket-way и следует это как-то запилить без eval?

С точки зрения racket-way макросы не следуюет использовать для оптимизаций. Особенно для микрооптимизаций. Компилятор, как правило, сделает не хуже. То есть, следует писать (play (for/vector ([i (in-range 2)]) (saw (* (+ i 1) 400))) 3) а оптимизацией заниматься только если точно уверен, что это узкое место.

Так что баг произошел из-за захвата переменной i в макросе play? А где тогда хваленая уберзащищенность ракета, которая должна не позволять заколизить переменную без явного указания кодера?

Твой макрос, правильно написанный, решал бы не ту задачу, что ты написал. У тебя (play (repl ([i (in-range 2)]) (saw (* (+ i 1) 400))) 3) транслировалось в

(play (vector (let ([i 1]) (saw (* (+ i 1) 400)))
              (let ([i 2]) (saw (* (+ i 1) 400)))))
Это рабочий код, но не совпадающий с постановкой задачи. А если постановку задачи решать корректно «в (saw (* (+ i 1) 400)) подставлять i при компиляции» то надо как-то указать, что именно в шаблоне должно заменяться.

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

Твой макрос, правильно написанный

Наконец-то понял чего именно ты хочешь. Чтобы для каждой переменной for динамически подставлялся синтаксис при раскрытии.

Получается вот такое:

(define-syntax (repl stx)
  (syntax-case stx ()
    [(_ ([id sequence-expr] ...) body)
     #`(vector #,@(syntax-local-eval
                   #`(for/list ([id sequence-expr] ...)
                       #`(let-syntax ([id (λ (stx) #'#,id)] ...)
                           body))))]))

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

У тебя ошибка была только в (cons vector ....) Должно было быть (cons 'vector ....).

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

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

Это всё делается не ради оптимизации, а ради компиляции в си. Кроме оптимизации у такого подхода + в минимизации ядра транслятора (минимальный набор примитивов, которые не успели подставиться еще в окружении ракета к началу трансляции). Но конкретно в данном случае всетаки придется рано или поздно расширять транслятор понятием функция (ну тоесть переходить от генерации простого терма, вычисляющего значение к генерации синтакса лямбды с описанием какие ей нужны параметры). Я просто надеялся отложить данную проблему на потом.

надо как-то указать, что именно в шаблоне должно заменяться

А я случаем не это пытался сделать с помошью let-syntax? Просто вспоминая наш спор про aif, с вариантом «вручную пробежаться по дереву кода и поподставлять» связываться не охота. Если ракет берет на себя заботу о правильной подстановке в выражение, то пусть он этим и занимается. Короче оригинальная идея заключалась в том, что я в компилтайме определяю макрос с именем var, который действует на конкретный клон переданного тела. Если не сложно, попробуй придумать как такое организовать. Вот реально же интересен этот ход сам по себе: подстановка переменных в выражение с помошью макротрансформера. Подстановка в смысле матлогики - оператор | или как там мы его записывали.

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

с вариантом «вручную пробежаться по дереву кода и поподставлять» связываться не охота

Это правильно. Разумных вариантов два: или явно указывать при использовании, что относится к шаблону, а что к параметру (через #,) или твой вариант с let-syntax.

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

(define-syntax (repl stx)
  (syntax-case stx ()
    [(_ ([id sequence-expr] ...) body)
     #`(vector #,@(syntax-local-eval
                   #`(for/list ([id sequence-expr] ...)                       
                       #`(let-syntax ([var (syntax-rules ()
                                             [(_ id ...) body])])
                           (var #,id ...)))))]))

Это всё делается не ради оптимизации, а ради компиляции в си.

В этом случае gcc тоже умеет раскручивать списки и выносить константы.

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

«Сам решает» — это искусственный интеллект?

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

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

В этом случае gcc тоже умеет раскручивать списки и выносить константы.

Что-то я немного сомневаюсь что он заинлайнит нечто вроде

double f(double* state, int idx) {
 return state[idx] + state[idx+1];
}
...
double state[MAX_COUNT+1];
double acc = 0;
for (int i = 0; i < getFCount(); ++i) {
  acc += f(state, i);
}

в

double state[MAX_COUNT+1];
int f = getFCount();
double acc = (f > 0? 1: 0) * (state[0] + state[1]) +
 (f > 1? 1: 0) * (state[1] + state[2]) ... ((f > MAX_COUNT-1)? 1: 0) * (state[MAX_COUNT-1] + state[MAX_COUNT]);

Но с другой стороны не факт что так будет быстрее, и надо просто проверять на тестах.

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

сомневаюсь что он заинлайнит нечто вроде

Если доступен исходник getFCount и она чистая или в заголовке для неё указано __pure, то заинлайнит (может вообще при компиляции вычислить и результат подставить).

Проверку на MAX_COUNT делать не будет, так как выход за границы массива — UB,

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

(f > 0? 1: 0) * (state[0] + state[1])

Ну точнее if (f <= 0) goto exit; если быть совсем оптимальным. Не уверен что (f > 0? 1: 0) оно выполнит без единого джампа, но можно и самому написать такую функцию тоже.

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

getFCount обычно делается так double getFCount() { return ui->fKnob->getValue(); } и нефейхоа она не чистая. Но поинлайнить всеравно можно, если известно что getFCount: IO (Int [0, 20]).

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

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

Это делает компилятор. Желание написать свой компилятор на макросах — нездоровое. Макросы должны либо вводить новый синтаксис, либо требовать для оптимизации какую-то информацию от программиста. Анализ dataflow лучше делать компилятором после раскрытия всех макросов.

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

double getFCount() { return ui->fKnob->getValue(); } и нефейхоа она не чистая

Если у тебя getValue() меняет fKnob, то это плохое название для getValue.

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

Проверку на MAX_COUNT

Где ты ее нашел. Я имел ввиду что я заинлайню MAX_COUNT раз, из которых выполню только getFCount() раз, остальное скипну.

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

Если у тебя getValue() меняет fKnob

Это функция нарушает чистоту по другому критерию: детерминированность. Никогда не знаешь что же она тебе вернет в очередной раз.

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

Я имел ввиду что я заинлайню MAX_COUNT раз

Если f < MAX_COUNT, особенно значительно меньше, то будет медленней: вместо f проверок ты сделаешь MAX_COUNT.

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

Ну я надеялся отыграться на более прямой адресации, но в принципе согласен - врядли оно того стоит. По поводу оптимизации во всяком случае было проверено, что std::vector сильно портит производительность по сравнению с простым массивом, даже когда выделяется он всего один раз. Так что уж тут говорить о вере в то, что gcc поймет какое подмножество его возможностей я использую и сообразит переписать алгоритм вычисления оптимальнее, особенно когда там станет много коду. Ну короче оставлю макросы на потом, доведу до ума пока все рантайм возможности. Когда будет уже транслятор, найду на чем продемонстрировать некоторые символические преобразования исходного синтакса, которые позволяют ускорить результат в разы. Я просто хотел убедиться, что такое в принципе возможно и удобно делать макросами.

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

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

Очень странно. Внутри std::vector тот же самый простой массив. Разве что .at использовали вместо [].

Я просто хотел убедиться, что такое в принципе возможно и удобно делать макросами.

Можешь посмотреть Как на макросах изобразить инстанциирование (комментарий) Там очень полезная схема для конструкций, аналогичных шаблонам C++.

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

Очень странно. Внутри std::vector тот же самый простой массив.

Может массив на стеке создавался?..

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

Он даёт нажать сколько угодно пока есть что раскрывать, но не раскрывая макросы стандартной библиотеки (внизу Macros hiding — можно настраивать).

Даже с выключенным хайдингом он начинает уже с той формы в которой все, что мне интересно уже раскрыто и раскрыто не так как я хотел. expand/step-text ктати тоже. Тоесть когда задаешь задачу заекспандить мой play, он начинает с того что сразу резко полностью подставляет #,(synth-def-sr-form sd) несмотря на то, что в sd есть тоже вызовы макросов и мне инетерсно как раскроются именно они. Может даже придется отказатся от ракета, если в нем так туго с отладкой.

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

Впрочем я конечно многого хочу, надо просто отдельно тестить sl->synth-def как отдельную функцию. Кстати вопрос, как доступится к символам, определенным в begin-for-syntax из репла или из макросов, определенных просто в модуле? Очень надо.

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

Очень надо.

http://pasterack.org/pastes/15193 более наглядный пример нафика мне макросы в моем ДСЛ. Я переписал saw через примитивы. Если я пытаюсь просто определить макрос для списка, который я пишу в репле, у меня нет доступа к символам, из которых строится ДСЛ (см. saw-err) и мне остается только одно: добавить saw в функцию транслятора, ибо только там у меня есть доступ к тому окружению. Оно вроде бы понятно, но както негибко и помоему в принципе не обходимо. Разве что вспомнить старый добрый трюк с (syntax-local-eval #'#'(let-syntax ..., но что-то мне подсказывает, что даже если и заработает, то так писать будет только хуже.

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

Кстати говоря (expand/step #'(play (saw-err 440 0.0) 3)) на самом то деле saw-err таки применил, хоть и толку от этого немного. Видимо я просто действительно спутал понятия подстановки макроса и трассировки кода тела макроса...

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

Кстати вопрос, как доступится к символам, определенным в begin-for-syntax из репла или из макросов, определенных просто в модуле

Я заменяю (begin-for-syntax ...) на (module m racket ...) (require (for-syntax 'm)) и тогда для отладки просто (require 'm) и можно тестировать.

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