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)
Ответ на: комментарий от q0tw4

https://github.com/Hikawa/synmak/tree/fefe23934a3b580a1295d592bff98c5b32f39b35 короче полный код, найти минимальный багсемпл тут непросто, надо воспроизводить сию богатую инфраструктуру. Вопщем проблема в том, что saw переехал в sounds.sexp, и когда read-syntax читает из него +, то уже при подстановке полностью скомпиленного play оно не видит у плюса биндинга и обламывается (пример (play (saw 440 0) (2))). И как тут помогут биндинги в макростеппере, которые просто числа какието непонятные?

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

Откати коммит на указанный в сообщении. Там затычка уже стоит, которая создает синтакс уже в модуле, а не на базе читаемого файла.

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

Я сделал тоже самое и ошибка есть.

(play (saw 440 0) (2))
. <unsaved editor>::66: +: unbound identifier;
 also, no #%top syntax transformer is bound in: +

Может скомпиленная версия не та подтянулась?

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

Увидел ошибку. В общем, посмотрел бы ты на include.rkt в коллекции racket — там правильный include.

А если вкратце, то надо добавить синтаксическое окружение тому, что вернул read-syntax. Если do-include из include.rkt слишком сложно, то хотя бы через (datum->syntax stx (syntax->datum ...)).

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

(datum->syntax stx (syntax->datum ...))

Ага и забыть строчки исходника, откуда что. Спасибо, но я уже сделал это, заменив read-syntax на read. Просто непонятно, почему в игрушечном примере, когда с файла читается (+ 1 1) и сразу евалится все работает, а как вставил в норм проект - лажа.

И вдогонку: пишу тут униттесты надо короче чтоб рекурсивное сравнение структур, когда натыкается на пару inexactов, сравнивало по |x - y| < e. Переопределение = и equal? не помогает. Просто узать check-= не вариант, ибо на входе не число, а вектор чисел. Мне что теперь писать свой equal? полностью?

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

Ага и забыть строчки исходника, откуда что.

Я же тебе написал место, откуда копипастить. Должно быть что-то вроде

(let ([lexed-content
                      (let loop ([content content])
                        (cond
                         [(pair? content)
                          (cons (loop (car content))
                                (loop (cdr content)))]
                         [(null? content) null]
                         [else
                          (let ([v (syntax-e content)])
                            (datum->syntax
                             ctx
                             (cond
                              [(pair? v) 
                               (loop v)]
                              [(vector? v)
                               (list->vector (loop (vector->list v)))]
                              [(box? v)
                               (box (loop (unbox v)))]
                              [else
                               v])
                             content
                             content))]))])
                 (datum->syntax
                  (quote-syntax here)
                  `(begin ,@lexed-content)
                  orig-stx))
monk ★★★★★
()
Ответ на: комментарий от q0tw4

почему в игрушечном примере, когда с файла читается (+ 1 1) и сразу евалится все работает

Потому что евалится. У eval своё пространство имён есть. А в define-syntax + read-syntax — нету.

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

Должно быть что-то вроде

О да, с таким же успехом я мог бы писать это в коммон лиспе. Правда там подобное пришлось бы писать еще несколько раз, чтоб довести язык до ракетообразности с возможностью делать правильный aif путем ручной обработки синтаксиса, о которой я говорил ранее. Одно только радует, что на входе в сей код мой ДСЛ, а не произвольный ракет, так что никаких потенциальных проблем с биндингом символов внутри (quote ...) или define-syntax-rule там просто нет.

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

чтоб рекурсивное сравнение структур, когда натыкается на пару inexactов, сравнивало по |x - y| < e

Для структур gen:equal+hash

Просто узать check-= не вариант, ибо на входе не число, а вектор чисел.

Так (map-vector (lambda (x) (check-= x y eps)) vec)

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

map-vector

А как же общий подход? https://github.com/Hikawa/synmak/blob/master/synth-test.rkt смотри как там все закручено. В принципе там может сравниваться вектор чего угодно, часто вектор векторов чисел. Так что надо писать my-equal? и передавать как предикат.

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

Так что надо писать my-equal? и передавать как предикат.

Тогда да. В принципе, если ограничится последовательностями, то всё не так уж и сложно.

(define (my-equal? a b pred)
  (cond
    [(sequence? a)
     (and (sequence? b)
          (for/and ([i (in-values-sequence a)]
                    [j (in-values-sequence b)])
            (my-equal? i j)))]
    [else (pred a b)]))
monk ★★★★★
()
Ответ на: комментарий от monk

define-syntax lexical-eval

> (define-syntax-rule (test x) (+ x 1))
> (lexical-eval '(test 3) test)
. test: use does not match pattern: (test x) in: test

Я просто внял твоему гласу и переписую обратно на функции с макросов (все таки плохо, когда вместо того, чтоб показать стектрейс на неверном дсл коде оно просто падает при компиляции и при это иногда даже не показывает на каком месте, просто сообщение и все, так я стер локацию в одном месте для удобства униттестов). Так вот, то что я говорил, что мне теперь надо заевалить синтакс, чтоб из синтакса проги получить данные, которые она считает. Но так как я писал в духе макроса, я там узаю макросы, которые делают set!-transformerы, так что мне теперь надо заевалить с захватом макроса блин. Варианты решения такие: дописать твой макрос чтоб он понимал символы ссылки на макросы или попробовать провернуть expand над моим кодом. Или внутри подъевального кода (require module) ...

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

Виноват, там просто недоимпортился этот модуль. Короче на самом деле надо модуль с макросами иметь в модуле сборщике синтакса не в for-template а в просто require, раз я его узаю с 0 фазы теперь. Странно это для меня. Допустим есть модуль A, в котором определен символ a, есть модуль B, в котором есть функция, которая вставляет в синтакс a из A. Модуль C делает (require B), а модуль D - (require (for-syntax B)). В итоге, чтоб модуль C при (eval то-что-дал-B) и D при (define-syntax ... то-что-дал-B) работали норм получается надо в B сделать (require A (for-syntax A))? А откуда B заранее будет знать куда его включат узеры?

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

получается надо в B сделать (require A (for-syntax A))

Да.

А откуда B заранее будет знать куда его включат узеры?

Он не должен знать. Разработчик должен смотреть, что и когда определяется. eval выполняется при выполнении программы => require. define-syntax при компиляции => for-syntax.

Если функция возвращает синтакс, значит нужен for-template

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

Так тут разные модули. Потенциально разные разработчики. Откуда автор B знает, как его заюзают. А может кто-то еще D заюзает в for-syntax и тогда автор того модуля должен залезть в B и прописать (require (for-meta -2 A))?

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

Так тут разные модули. Потенциально разные разработчики. Откуда автор B знает, как его заюзают.

Ещё раз. Смотри сигнатуры функций. Если хоть одна функция возвращает syntax, надо писать for-template.

А (require (for-meta -2 A)) надо делать, если у тебя будет функция наподобие

(define (meta2 stx)
  (syntax-case stx ()
    [(_ x) #'(lambda (stx2) 
               (syntax-case stx2 ()
                 #'(call-from-meta2 x)))]))

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

А если в другом модуле кто-то сделает

(define (meta2 stx) (syntax-case stx ()
  [(_ x) #`(meta1 #,x)]))

То символы, которые узает meta1, его же родной модуль должен иметь в -2 так ведь? Причем именно в модуле, где описан meta1. Там где символ лексически расположен, там он и захватит все биндинги всех фаз и потом уже ничего, что лексически там не было при компиляции того модуля, туда подсунуть не выйдет.

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

То символы, которые узает meta1, его же родной модуль должен иметь в -2 так ведь

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

(define (meta2 stx) (syntax-case stx ()
  [(_ x) #`(meta1 #,#'x)]))
или (define (meta2 stx) (syntax-case stx () [(_ x) (meta1 #'x)]))

В первом случае meta1 является просто функцией и никаких особенностей нет. Во втором --- функцией syntax -> syntax => если он добавляет свои символы, они должны быть в for-template

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

(datum->syntax stx (syntax->datum ...)). Или пример приведи, может я не понял.

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

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

Итак создай у себя папку со следущими файлами (не разобрался как в одном модули делать и инклюдить друг в друга). Файл «a.rkt»

#lang racket
(provide f)
(define (f x) (+ x 1))

b.rkt

#lang racket
(require "a.rkt" (for-template racket "a.rkt"))
(provide meta1 meta1-err)
(define (meta1 x) #`(f #,x))
(define (meta1-err x) #`(g #,x))

c.rkt

#lang racket
(require "b.rkt")
(define doit (eval-syntax (meta1 1)))
;(define doit-err ((eval-syntax #`(lambda (g) #,(meta1-err 1))) (lambda (x) (+ x 2))))
;b.rkt:5:25: g: undefined; cannot reference undefined identifier

d.rkt

#lang racket
(require "b.rkt" (for-syntax "b.rkt"))
(provide meta2)
(define-syntax (meta1-test stx)
  (syntax-case stx (meta1-test)
    [(meta1-test x) (meta1 (syntax-e #'x))]))
(define doit (meta1-test 2))
(define-syntax (meta2 stx)
  (syntax-case stx (meta2)
    [(meta2 x) #`(meta1 #,(syntax-e #'x))]))
(define doit2 (meta2 3))

e.rkt

#lang racket
(require (for-syntax "d.rkt"))
(define-syntax (meta2-test stx)
  (syntax-case stx (meta2-test)
    [(meta2-test x) (meta2 (syntax-e #'x))]))
(define doit (meta2-test 4))
q0tw4 ★★★★
()
Ответ на: комментарий от q0tw4

Но зато про лексический захват пример вышел удачный (см. закоментированный код в c.rkt, он по идее должен был бы работать, но нет, ракет злой)

Не должен. Гигиена, сэр. В смысле, (define (meta1-err x) #`(g #,x)) создаёт новый символ g каждый раз.

А вот так должен

(define (meta1-err x) #`(#,(datum->syntax #'x 'g) #,x))

Но на самом деле получаем странную феерию:

> ((eval-syntax #`(lambda (g) #,(meta1-err 1))) (lambda (x) (+ x 2)))
. . b.rkt:5:24: g: undefined;
 cannot reference an identifier before its definition
> ((eval-syntax (expand-once #`(lambda (g) #,(meta1-err 1)))) (lambda (x) (+ x 2)))
3

То есть eval-syntax не всё почему-то видит...

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

То есть eval-syntax не всё почему-то видит

Что-то нашёл. expand-once добавляет лексический контекст. Если вместо expand-noce поставить expand-syntax-once, то тоже не работает.

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

В общем возвращаемся к утверждению, о том что гигиена это конечно хорошо, но любая ее реализация выглядит слишком надуманно, ломает мозги и требует таких плясок с бубном, что в них немудрено и реальные макробаги пропустить, когда начинаешь (datum->syntax stx (syntax->datum ..)) и evalы всякие применять, чтобы сделать таки то, что задумал изначально. Но в принципе для фана подходит лучше, чем эзотерика всякая нудная, так что можно и поузать иногда.

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

Нашёл. Я с типами запутался.

В b.rkt

(define (meta1-err x) #`(#,(datum->syntax x 'g) #,x))

В c.rkt

(define doit-err ((eval-syntax #`(lambda (g) #,(meta1-err #'1))) (lambda (x) (+ x 2))))

Работает.

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

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

Отсутствие гигиены ломает мозг гораздо сильнее. Посмотри на потроха cl-iterate, например. Опять же, если она точно не нужна (вместе с информацией об источнике символа), то сбросить весь контекст в контекст запроса всегда можно одной командой.

когда начинаешь (datum->syntax stx (syntax->datum ..)) и evalы всякие применять, чтобы сделать таки то, что задумал изначально

Если понимаешь, что делают команды, то ничего необычного не происходит. А если не очень, так и в CL человек тут (на форуме) макросы писал через eval. Так как считал, что единственные правильные макросы — это fexpr'ы.

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

Я просто жалуюсь, что нет тулзов работы с неймспейсом. Ну почему у меня 1 из 2 либо узать то, что захватил символ при своем определении либо забыть вообще все и переинтернить выражение заново. Я вот что-то пробовал еще с частичной обработкой выражения, типа #`(... #,(datum->syntax stx (syntax-e exp))), что минимум нужную локацию в сорце выставляет на случай бектрейсов. Но этого мало. Хочется быть хозяином положения и мочь сделать что-то вроде (eval-syntax (bind (meta1-err 1) (g x) (+ x 2))), который будет работать независимо от того, откуда в b.rkt взят g. Впрочем на практике обычно хватает просто правильно прописать в b.rkt (require X (for-syntax X)), как я и сделал с f.

А да, я в принципе старался, чтоб аргументом был integer, а не syntax. Или мог вообще без аргумента писать. Так что не факт, что в (datum->syntax x 'g) у нас будет этот самый x в наличии.

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

(bind (meta1-err 1) (g x) (+ x 2))

Это что должно вернуть?

который будет работать независимо от того, откуда в b.rkt взят g

Заворачивай в (expand-once ...). Обычно этого хватает.

обычно хватает просто правильно прописать в b.rkt (require X (for-syntax X)), как я и сделал с f.

Если ты про b.rkt, то там (require X (for-template X)). И на самом деле достаточно (reguire (for template «a.rkt»)), так как f присутствует только в синтаксисе.

А да, я в принципе старался, чтоб аргументом был integer, а не syntax.

Тогда склейку контекстов надо проводить снаружи от g. Как ты написал (bind ...).

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

так как f присутствует только в синтаксисе

А ты попробуй убрать «a.rkt» из require. c.rkt перестанет компилиться, так как его евал активирует вычисления на 0 фазе. Вот этот момент меня и бесил все это время.

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

Вот этот момент меня и бесил все это время.

Понял. Действительно, eval-syntax несколько сбивает с толку.

Делай вместо него

(define (eval-syntax* stx)
  (eval-syntax (syntax-shift-phase-level stx 1)))

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

Хотя тоже не совсем выход. Тогда приходится b импортировать на две фазы. Но хоть b не зависит от своих пользователей.

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

Я вообще непонимаю, какой прок от фаз. Они как универсумы в DT языках, что-то разделяют, парадоксы разрешают, но кодеру только мешают. Как там в ракете сделать импорт сразу во все фазы? разве нет такой фичи?

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

Хотя да, без фаз гигиену ж не напишешь. Печалько. Интересно, а можно ли как-то придумать гигиену без фаз?

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

Я вообще непонимаю, какой прок от фаз.

Чтобы иметь повторяемую компиляцию. После компиляции всё, кроме нулевой фазы выкидывается.

Как там в ракете сделать импорт сразу во все фазы? разве нет такой фичи?

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

Есть модуль для всех фаз. Символы из него идентичны во всех фазах. Но он может импортировать только модули такого же типа (всефазные).

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

Хотя да, без фаз гигиену ж не напишешь

С чего это? В Scheme R6RS гигиена и syntax-case есть, а фаз нет. Вот нормальные модули без фаз — проблематично. В том смысле, что модули, используемые при компиляции не должны загружаться в скомпилированную программу.

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

Ага, круто. Но меня пока волнует иное. Я вот думаю заделать макрогенерацию typed/racket кода оставляя весь генерирующий код в untyped. И как мне это блин провернуть? Ну допустим (require typed-racket/base-env/base-types), чтоб выдернутые отсудова #'Integer стали типами. И то не факт, что сработает. Ну а чтоб евалить наверно заведу маленький typed модуль. Или может ну его, в С компиляторе уже потипизирую?

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

Я вот думаю заделать макрогенерацию typed/racket кода оставляя весь генерирующий код в untyped. И как мне это блин провернуть?

; a.rkt
#lang racket
(require (for-template typed/racket))

(provide make-stx)

(define (make-stx stx)
  (syntax-case stx ()
    [(_) #'(lambda ([x : String]) (string-append x "bar"))]))

;b.rkt
#lang typed/racket
(require (for-syntax "a.rkt"))

(define-syntax (test stx)
  (make-stx stx))
monk ★★★★★
()
Ответ на: комментарий от q0tw4

Или может ну его, в С компиляторе уже потипизирую

Кстати, если тебе нужны гигиенические макросы и типы для Си, а не как самостоятельный язык, то можешь посмотреть на http://nim-lang.org/

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

Ну ты же видишь, что у меня довольно умная компиляция. В чужом ЯП, написанным непроверенным васей, я буду долго и с матюками осваивать макросы до такого уровня, чтоб осилить то, что я не без твоей помощи, но все же без особого напряга делаю ракетом. И вообще ним несколько убог. Если на то пошло, можно было бы попробовать макросами раста, но опять же, в деле ДСЛинга нет никого круче ракета. Макрораст я может быть буду узать, когда буду писать игру, ну чтобы генерировать методы доступа к шейдерным переменным и прочую линейную писанину

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

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

Я предполагал, что твой результат чем-то будет похож на ним. Там есть гигиена в макросах, компилируется в Си и нет фаз.

Если на то пошло, можно было бы попробовать макросами раста

Не. Там реально ужас. Во-первых, синтактически, во-вторых, там нет syntax-case, а есть только syntax-rules. Нормальные макросы можно делать через плагины компилятора, но там ещё и документации почти нет.

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

Думаешь в ниме я смогу во время компиляции прочитать файл и вообще делать что вздумается? Вообще весь этот проект затеян ради оптимизиции кода. Иначе мне хватило бы просто написать библиотеку классов вместо целого языка. Хотя не совсем, выразительность у классов так себе, слишком уж много страданий доставляет написание ДСЛ-костылей на С++. Ну в общем пиши я на нелиспе, у меня сразу же возникнут следующие проблемы: надо определится с синтаксисом ДСЛ, надо организовать ему парсер, надо эту всю инфраструктуру поднять в компилтайм (например в С++ такое вылилось бы в полное переписывание и невозможность реализовать в ДСЛ команду include). А да и еще выучить новый ЯП и его макроЯП. Сразу все желание пропадает. А так в ракете это все как игра: раз написал простые звуки, 2 - добавил события, 3 - добавил типы, 4 - добавил генерацию кода. Так вот постепенно и без героических наскоков шаг за шагом выращивается мой собственный синтезатор.

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

Думаешь в ниме я смогу во время компиляции прочитать файл и вообще делать что вздумается?

Да. Судя по http://nim-lang.org/docs/manual.html#macros-expression-macros

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

На любом языке с нормальными макросами эти вопросы не возникают. Так как ДСЛ определяется языком, парсер и инфраструктура в коробке. Racket даёт только преимущество писать макросы для чужого синтаксиса (см honu или тот компилятор брейнфака, что я тебе ссылку давал).

А да и еще выучить новый ЯП и его макроЯП.

Это да.

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

Так как ДСЛ определяется языком

В смысле для каждой моей фишки (блин не знаю как правильно называется то что я сейчас пишу, так как это не стрелки, но близко к ним, ну FRP короче) подбирается наиболее подходящее понятние в целевом языке (обычно это класс, ибо ничего иного достаточно подходящего там просто нет) и далее собирается лес костылей, чтоб выглядело похоже на то, что было в задумке. И это путь неудачников, не познавших силу лиспа. Путь лиспа предполагает описание необходимых абстракций в синтаксисе скобок (что никак не мешает выразительности) и последущее транслирование сего в нечто вычислимое. По сравнению с этим, впихиванием стрелок в классы такой костылизм, что лучше уж тогда на мозге транслировать и писать сразу результат на голых сях. Вобщем если начинать такой проект на нелиспе, это однозначно будет flex -> bison -> translator -> gcc. И ни о каких макросах нет и речи, так как всю эту махину в компилтайм не затянешь.

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

но там ещё и документации почти нет.

Ну информация имеется, не так уж её и мало. Например, вот. В официальной документации не так много потому что они ещё «не стабильные».

Про ужасность (обычных) макросов вынужден согласиться.

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

обычно это класс, ибо ничего иного достаточно подходящего там просто нет

Если мы всё ещё про nim, то макрос там определяется как любая синтаксическая конструкция языка. Можно делать лиспообразно play(def(sound(x), saw(x*200, 0)), repl(i, 2, sound(i+1))) можно в стиле nim:

play:
  proc sound(x : int):
    saw(x*200,0)
  for i in 0..2:
    sound(i+1)

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

И где гарантии, что я там не обломаюсь на очередном баге компилятора? В ракете есть некий monk, который всегда выручит, есть irc, где отвечают с приличной вероятностью, да и вообще я о нем знаю уже десяток лет, еще в универе лабы писал (но в макросы не лез само собой). О ниме только недавно услышал. А вдруг он как идрис - наколенная поделка скучающего чувака. А я потеряю неделю на вкуривание и попорчу себе настроение об явные баги компилера. Ну или скорость будет не фонтан. И вообще ракет как раз попер. Впрочем генерация си кода станет проблемой, так что если есть ЯП, на который можно переписать мое творение и при этом получить нужную скорость не прибегая к генерации сорцов, можно и попробовать...

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

И где гарантии, что я там не обломаюсь на очередном баге компилятора?

Никаких. Впрочем, для Racket тоже никаких.

А вдруг он как идрис - наколенная поделка скучающего чувака.

https://github.com/nim-lang/Nim — 190 разработчиков. 717 issues

для сравнения https://github.com/racket/racket — 141 разработчик, 59 issues.

Ну или скорость будет не фонтан.

Вряд ли меньше, чем у Racket. https://github.com/kostya/benchmarks

И вообще ракет как раз попер.

Это да.

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

Поэтому и предлагаю.

У Nim'а только два серьёзных недостатка по сравнению с Racket:

1. Принципиальная типизированность всего => макросы писать сложнее

2. Нет возможностей Racket, которые сложно реализовать в Си: продолжения, слабые ссылки, зелёные потоки, ...

Ну и привязка к синтаксису более жёсткая. В Racket всё-таки есть #lang, который позволяет прикрутить произвольный синтаксис, а в Nim придётся брать встроенный питоноподобный.

Зато компиляция в Си из коробки.

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

Вряд ли меньше, чем у Racket.

Дык я имел ввиду скорость сгенеренного моей прогой сикода))))

Нет возможностей Racket, которые сложно реализовать в Си

Конкретно к моей задаче на это все пофику

Хмм, а там можно как в ракете, написать функцию, которая генерит АСТ в рантайме, а потом уже вызвать ее в макросе? А то как блин униттестить и отлаживать, если вместо исключения пример инвалидного кода порождает ошибку компиляции. И как там с хранением строки исходника в АСТ?

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

Хмм, а там можно как в ракете, написать функцию, которая генерит АСТ в рантайме, а потом уже вызвать ее в макросе?

Разумеется.

proc gen(e: stmt) : stmt =
  # здесь генерим АСТ из e
  ...
  ...

macro play(e: stmt) =
  result = gen(e)

Если потом надо выкинуть функцию из скомпилированного кода (оставить только на время компиляции), то http://nim-lang.org/docs/manual.html#pragmas-compiletime-pragma

И как там с хранением строки исходника в АСТ

Судя по документации, никак.

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