LINUX.ORG.RU

Объявление функции внутри макроса, чтобы она была доступна

 , ,


1

2

Можно ли в Racket в макросе объявить функции, которые бы использовала вложенная в этот макрос функция?

т.е.

(define-syntax some-shit
 (syntax-rules ()
 [(some-shit a b)
  ((lambda() 
    (define proc1 "ok")
    (define proc2 "ok2")
    (a b)))]))

И в другом пакете:

 (some-shit (lambda (val) (string-append proc1 b))
            "heheh")

Беда в том, что макрос находится в отдельном пакете от основного кода.

★★★

Схему начал забывать, но там, кажется, гигиена может помешать. В CL легко было бы сделать

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

В CL легко было бы сделать

Вот этой фразой ты мне считай ответ и дал - сделал через define-macro и макросом в легаси стиле.

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

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

Гигиена тут не при чём, define «работает» в лексическом окружении, в отличие от CL defun.

korvin_ ★★★★★
()

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

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

Хотя, пардон, в данном случае всё-таки при чём.

korvin_ ★★★★★
()

Беда в том, что макрос находится в отдельном пакете от основного кода.

Нет, не в этом.

Ну, например, так:

(define-syntax some-shit
  (syntax-rules ()
    ((some-shit p1 p2 a b)
     (begin
       (define p1 "ok")
       (define p2 "ok2")
       (a b)))))

(some-shit proc1 _ (lambda (val) (string-append proc1 val))
           "heheh")

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

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

Собственно моему говнокоду нужно было примерно вот это:

(require compatibility/defmacro)

(define-macro (my-macro func)
  `((λ()
      (define mine-list (list "Initial element "))

      (define (add-to-list element)
        (set! mine-list (append mine-list (list element))))

      (,func)

      (map (λ (element) (format element)) mine-list))))

(my-macro (λ ()
            (add-to-list "Hello ")
            (add-to-list "World ")))
nihirash ★★★
() автор топика
Ответ на: комментарий от nihirash

Рекомендуемый метод это сделать: https://docs.racket-lang.org/reference/stxparam.html

То есть должно быть так:

#lang racket
(provide my-macro add-to-list)
(require racket/stxparam)

(define-syntax-parameter add-to-list
  (λ (stx)
      (raise-syntax-error #f "use of add-to-list not in my-macro" stx)))

(define-syntax my-macro
  (syntax-rules ()
    [(my-macro func)
     (let ([mine-list (list "Initial element ")])
       (define (add-to-list-f element)
        (set! mine-list (append mine-list (list element))))

       (syntax-parameterize ([add-to-list (syntax-rules () [(_ x) (add-to-list-f x)])])
         (func))
       
       (map (λ (element) (format element)) mine-list))]))
monk ★★★★★
()
Ответ на: комментарий от nihirash

А если надо ровно это (с одного имени снять гигиену), то

(define-syntax (my-macro stx)
  (syntax-case stx ()
    [(my-macro func)
     #`(let ([mine-list (list "Initial element ")])
         (define (#,(datum->syntax stx 'add-to-list) element)
           (set! mine-list (append mine-list (list element))))

         (func)
       
         (map (λ (element) (format element)) mine-list))]))

monk ★★★★★
()

В общем случае (для любой Scheme)

(define-syntax (some-shit stx)
 (syntax-case (stx)
 [(some-shit a b)
  #`((lambda() 
    (define #,(datum->syntax stx 'proc1) "ok")
    (define #,(datum->syntax stx 'proc2) "ok2")
    (a b)))]))

Или (для Racket)

(define-syntax (some-shit stx)
 (syntax-case (stx)
 [(some-shit a b)
  (with-syntax ([proc1 (syntax-local-introduce #'proc1)]
                [proc2 (syntax-local-introduce #'proc2)])
    #`((lambda() 
      (define proc1 "ok")
      (define proc2 "ok2")
      (a b))))])

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