LINUX.ORG.RU

макрос, генерация объявлений

 


0

2

Как определить простой макрос, который получает два символа на вход и определяет новый, являющийся результатом их конкатенации?

пытаюсь так - не работает:

#lang racket

(define-syntax (suffixify stx)
  (syntax-case stx ()
    [(_ sym suffix)
     (let ([id (string->symbol (format "~a~a"
                                       (syntax->datum #'sym)
                                       (syntax->datum #'suffix)))])
       
       #`(define #,id 'something))]))

;; (suffixify wtf ?)
;; wtf? => 'something


у твоего id лексический контекст самого макроса, а не того места где макрос был раскрыт, поэтому и undefined

вот это должно работать:

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

(define-syntax (suffixify stx)
  (syntax-case stx ()
    [(_ sym suffix)
     (with-syntax ([id (format-id stx "~a~a" #'sym #'suffix)])
       #'(define id 'something))]))

обрати внимание на второй аргумент функции format-id

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

syntax->datum зря выкинул

(suffixify a 2)

format-id: contract violation
  expected: (or/c string? symbol? identifier? keyword? char? number?)
  given: #<syntax:11:15 2>

Фактически, qweqwe пропустил только datum->syntax после string->symbol

#lang racket

(define-syntax (suffixify stx)
  (syntax-case stx ()
    [(_ sym suffix)
     (let ([id (datum->syntax stx (string->symbol (format "~a~a"
                                       (syntax->datum #'sym)
                                       (syntax->datum #'suffix))))])
       
       #`(define #,id 'something))]))
работает как ожидается.

К слову, синтаксис можно брать не обязательно stx (datum->syntax #'sym ...) работает ещё лучше (тогда контекст берётся из символа, а не всей конструкции suffixify).

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

странно что format-id вообще принимает (syntax blabla)

потому что (identifier? #'a) = #t

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

Вообще, как я понимаю, для racket правильнее использовать syntax-local-introduce:

(define-syntax (test stx)
  (with-syntax ([id (syntax-local-introduce #'foo)])
    #'(define id 1)))

(test)
foo

(define-syntax (test2 stx)
  (with-syntax ([id (datum->syntax stx 'foo2)])
    #'(define id 1)))

(test2)
foo2
вроде все хорошо:
Добро пожаловать в DrRacket, версия 6.0 [3m].
Язык: racket [выбранный].
1
1
> 
но немного усложним пример и сделаем макрос, который будет раскрываться в test/test2:
(define-syntax (test stx)
  (with-syntax ([id (syntax-local-introduce #'foo)])
    #'(define id 1)))

(define-syntax (test2 stx)
  (with-syntax ([id (datum->syntax stx 'foo2)])
    #'(define id 1)))

(define-syntax-rule (yoba1)
  (test))

(define-syntax-rule (yoba2)
  (test2))

(yoba1)
foo

(yoba2)
foo2
и оп-ля:
Добро пожаловать в DrRacket, версия 6.0 [3m].
Язык: racket [выбранный].
. foo2: unbound identifier in module in: foo2
> 
А если и пользоваться datum->syntax, то надо всегда четко понимать контекст какого символа мы хотим взять. В данном случае какова семантика макроса? Мы берем некий идентификатор и делаем из него новый с другим именем. Значит и брать надо контекст идентификатора, а не контекст всей формы макровызова:
(define-syntax (suffixify stx)
  (syntax-case stx ()
    [(_ sym suffix)
     (with-syntax ([id (format-id #'sym "~a~a" #'sym #'suffix)])
       #'(define id 'something))]))

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

Не подскажешь где описывается это понятие контекста и что и в какой момент времени при разворачивании макросов им является? Что-то я не могу осилить. От многообразия информации в guide/reference голова быстро болеть начинает, примеров недостаточно. Есть способ попроще? Или это пройдет со временем?)

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

Реальная задача вообще такая - есть константный набор списков такого формата: первый элемент каждого списка из набора - идентификатор, второй - произвольный список, содержащий другие идентификаторы

например:

((id1 (list input-id))
 (id2 (list 1 id1))
 (id3 (list 1 (list id1 (list id2 2)))))
макрос получающий на вход суффикс и input-id должен добавить к каждому, кроме input-id, идентификатору этот суффикс и подставить input-id.
(produce-definitions sfx some-id)

;; =>

(begin
  (define id1-sfx (list some-id))
  (define id2-sfx (list 1 id1-sfx))
  (define id3-sfx (list 1 (list id1-sfx (list id2-sfx 2)))))

сделал так:

#lang racket

(require (for-syntax racket/function))

(define-syntax (produce-definitions stx)
    
  (syntax-case stx ()
    [(_ suffix input-id) 
     
     (letrec ([parametrizable-sexps `((id1 (list ,#'input-id))
                                      (id2 (list 1 id1))
                                      (id3 (list 1 (list id1 (list id2 2)))))]
                         
              [id-list (map car parametrizable-sexps)]
              [suffixify (λ (sym) (string->symbol (format "~a-~a" sym (syntax->datum #'suffix))))]
              [convert-sexp (λ (sexp) (foldr (λ (v l)
                                                (cond [(list? v) (cons (convert-sexp v) l)]
                                                      [(memq v id-list) (cons (suffixify v) l)]
                                                      [else (cons v l)]))
                                             '()
                                             sexp))])

       (datum->syntax stx (cons 'begin (map (compose (curry cons 'define) convert-sexp)
                                            parametrizable-sexps))))]))
но опять таки преобразовывыю через syntax->datum и обратно. Тут, вроде как, нехорошо так делать . Контекст наугад подставил. Как это более идиоматичным к языку будет выглядеть?

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

Тут недавно была тема, что макросы сосут. Лишнее тому подтверждение. А в нормальных ЯП вот так:

(define-macro (suffixify sym_ suffix) (set (sym (string sym_ suffix)) 'something))

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

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

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

Newlisp
нет нормального GC
автор неосилил cons ячейки
нет промоушена в bignums
нет полноценных замыканий
динамический скоупинг
шутка вместо ООП
нет макросов, а значит нет намека на compile-time оптимизации
Мощность
mfw

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

syntax->datum нормально. А вот convert-sexp — явный признак того, что делается что-то не так.

Правильно должно быть как-то так:

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

(define-syntax (make-maker stx)
  (syntax-case stx ()
    [(_ producer input-id ((id val) ...))
     #'(define-syntax (producer stx)
         (syntax-case stx ()
           [(_ suffix input-val)
            (with-syntax ([id (syntax-local-introduce 
                                (format-id #'id "~a~a" (syntax-e #'id) 
                                                       (syntax-e #'suffix)))] ...
                          [input-id #'input-val])
              #'(begin (define id val) ...))]))]))

(make-maker produce-definitions input-id 
            ((id1 (list input-id))
             (id2 (list 1 id1))
             (id3 (list 1 (list id1 (list id2 2))))))

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

Язык с фекспрами нельзя компилировать. Такие дела.

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