Стандартный способ обработки цитируемого символа в макросах lisp в Scheme - PullRequest
0 голосов
/ 15 марта 2020

Для некоторого кода, с которым я работал, мне нужно было обработать 'x внутри макроса. Каков стандартный способ обработки этих значений?

У меня есть такой код:

(define (quoted-symbol? x)
   (and (pair? x) (eq? (car x) 'quote) (symbol? (cadr x)) (null? (cddr x))))

(define-macro (test x)
   (if (quoted-symbol? x)
      `(begin
          (display ',(cadr x))
          (newline))))

(test 'hello) ;; 'hello will be expanded into list (quote hello)

Это то, как это должно быть обработано, или просто в макросе вы не используете символы в кавычках ?

ПРИМЕЧАНИЕ : я не спрашиваю о гигиенических c макросах (я спрашиваю о реальных макросах lisp), поэтому, пожалуйста, не отвечайте с помощью гигиенических c макросов.

РЕДАКТИРОВАТЬ :

Мой макрос работает правильно в Guile и BiwaScheme и в моей собственной схеме, как lisp в JavaScript. Вот лучший пример:

(define-macro (test x)
   (if (quoted-symbol? x)
       `',(cadr x)))

(define (example arg)
  (list arg (test 'world)))

(example 'hello)

вопрос был не о display, а о (cadr x).

EDIT2 : Вы задали этот вопрос здесь go, мой макрос:

(define-macro (--> expr . code)
  "Helper macro that simplify calling methods on objects. It work with chaining

   usage: (--> ($ \"body\")
               (css \"color\" \"red\")
               (on \"click\" (lambda () (print \"click\"))))

          (--> document (querySelectorAll \"div\"))

          (--> (fetch \"https://jcubic.pl\") (text) (match /<title>([^<]+)<\/title>/) 1)

          (--> document (querySelectorAll \".cmd-prompt\") 0 \"innerText\")"
  (let ((obj (gensym)))
    `(let* ((,obj ,(if (and (symbol? expr) (not (null? (match /\./ (symbol->string expr)))))
                       `(.. ,expr)
                       `,expr)))
       ,@(map (lambda (code)
                (let ((name (gensym))
                      (value (gensym)))
                  `(let* ((,name ,(cond ((quoted-symbol? code) (symbol->string (cadr code)))
                                        ((pair? code) (symbol->string (car code)))
                                        (true code)))
                          (,value (. ,obj ,name)))
                     ,(if (and (pair? code) (not (quoted-symbol? code)))
                         `(set! ,obj (,value ,@(cdr code)))
                         `(set! ,obj ,value)))))
              code)
       ,obj)))

;; ---------------------------------------------------------------------------------------
(define (quoted-symbol? x)
   "(quoted-symbol? code)

   Helper function that test if value is quoted symbol. To be used in macros
   that pass literal code that is transformed by parser.

   usage:

      (define-macro (test x)
         (if (quoted-symbol? x)
             `',(cadr x)))

      (list 'hello (test 'world))"
   (and (pair? x) (eq? (car x) 'quote) (symbol? (cadr x)) (null? (cddr x))))

макрос используется в моей схеме как lisp в JavaScript, например, строка do c предлагает:

(--> document (querySelectorAll ".class") 0 "innerText")

Я хочу для поддержки:

(--> document (querySelectorAll ".class") 0 'innerText)

Код можно протестировать в Интернете по адресу: https://jcubic.github.io/lips/ (код необходимо скопировать / вставить, поскольку в текущей версии разрешены только вызовы методов).

Чтобы получить расширение, вы можете использовать

(pprint (macroexpand (-->  document (querySelector "x"))))

, если оно не работает (не расширяется), это означает, что макрос как-то не работает.

точка - это встроенная функция, которая получить свойство объекта и .. макрос:

(define-macro (.. expr)
  "(.. foo.bar.baz)

   Macro that gets value from nested object where argument is comma separated symbol"
  (if (not (symbol? expr))
      expr
      (let ((parts (split "." (symbol->string expr))))
        (if (single parts)
            expr
            `(. ,(string->symbol (car parts)) ,@(cdr parts))))))

, которые можно использовать для получения вложенного свойства, например (.. document.body.innerHTML)

1 Ответ

0 голосов
/ 15 марта 2020

Схема не имеет "настоящих макросов LISP". В некоторых реализациях есть что-то похожее, но формы имеют разные имена и использование. Они вообще не портативны.

Стандартный способ обработки 'x - обрабатывать его как выражение, которое оценивается в расширении. Например.

(define var 'x)

(test 'x)
(test var)

Две test формы должны составлять одинаковые, даже если макрос test получает (quote x) в первом и символ var во втором. На момент расширения var не существует, поскольку реализация может развернуть все макросы перед запуском.

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

(define (example arg)
  (list arg (test 'w)))

Когда это определено, вы печатаете 'w или (quote w) с новой строкой, а затем процедура, которую он пытается сохранить:

(define (example arg)
  (list arg #<undefined>))

Обратите внимание, что составляет Неопределенное значение выбирается реализацией, но я точно знаю, что во многих реализациях вы не можете оценить #<undefined>.

...