Как сделать "определить", который принимает строку в первом параметре в схеме SISC?

Давайте назовем эту функцию "динамически определяемой".

В основном я хочу написать макрос или лямбду, которая работает так:

$ (dynamic-define "variable" 123)
$ variable
$ => 123

Я попробовал это:

(define-syntax dynamic-define
    (syntax-rules ()
      ((_ string <body>)
       (eval `(define ,(string->symbol string) <body>)))))

и это работает, как ожидалось, но не кажется хорошим решением.

Я пытался использовать без Eval, как это:

(define-syntax dynamic-define                                           
    (syntax-rules ()                                                            
      ((_ string <body>)                                                        
       (define (string->symbol string) <body>))))

Но когда я пытаюсь использовать, я получаю эту ошибку:

Error: invalid syntax (define (string->symbol "variable") 123)

Что я должен делать?

(ПОЖАЛУЙСТА: отредактируйте этот вопрос, чтобы он соответствовал родному английскому, и удалите эту строку, пожалуйста)

2 ответа

Вы сталкиваетесь с фундаментальной проблемой: вы не можете сделать реальное динамическое определение "чистым" способом, поэтому вы пытаетесь использовать eval, Обратите внимание, что оба вышеупомянутых решения не являются динамическими - все, что они дают вам, это возможность писать "foo" вместо foo, Как я уже говорил в другом месте, используя eval обычно плохо, и в этом случае это хуже, так как это eval это используется из макроса, что делает его очень странным. Это в дополнение к неявной квази-кавычке в вашем макросе, которая делает вещи еще более запутанными. С таким же успехом вы можете определить все это как простую функцию:

(define (dynamic-define string <body>)
  (eval `(define ,(string->symbol string) ,<body>)))

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

(dynamic-define "foo" 123) ; instead of (define foo 123)

но как будет выглядеть реальное динамическое определение, которое принимает строку? Вы, вероятно, ожидаете, что это определит b:

(define a "b")
(dynamic-define a 123)

но это становится еще более запутанным, когда вы рассматриваете, как оно взаимодействует с другими привязками. Например:

(define y 123)
(define (foo s)
  (define x 456)
  (dynamic-define s 789)
  (+ x y))

Теперь, предполагая, что dynamic-define делает то, что вы хотите, подумайте о том, что вы получите с (foo "x") а также (foo "y"), Хуже считать (foo "s") а также (foo "+"), И что еще хуже

(foo (random-element '("x" "y" "s" "+" "define")))

? Понятно, если это dynamic-define действительно дает некоторое динамическое определение, тогда нет смысла, что вы можете сделать из этого кода, не зная заранее, какое имя foo будет вызван с. Не имея смысла в этом, компиляция уходит в окно, но гораздо важнее то, что правильность (или вообще смысл вашего кода) умирает.

По моему опыту, этот тип шаблона намного лучше обрабатывается с помощью хеш-таблиц и подобных устройств.

с помощьюdefine-macro

#> (define-macro (dynamic-define varstr val)
      `(define ,(string->symbol varstr) ,val))

#> (dynamic-define "variable" 123)
#> variable
123

с помощьюsyntax-case

#> (define-syntax dynamic-define
     (lambda (stx)
       (syntax-case stx ()
         ((k varstr val)
          (with-syntax ([var (datum->syntax-object 
                              #'k
                              (string->symbol (syntax-object->datum #'varstr)))])
            #'(define var val))))))

#> (dynamic-define "variable" 123)
#> variable
123
Другие вопросы по тегам