Добавление макросов в схему

#macros #scheme #lisp

#макросы #схема #lisp

Вопрос:

Для проекта колледжа мы работаем над learning scheme, однако нам пришлось выполнить сложное задание с небольшими знаниями. Нам предоставляются определенные функции, такие как «‘let», «‘cond», «and'» и т.д., И нас просят добавить макросы.

 (define eval
  (λ (e env)
    (cond ((symbol? e) (lookup-var e env))
          ((not (list? e)) e) ; non-list non-symbol is self evaluatory
          ;; special forms go here:
          ((equal? (car e) 'λ)      ; (λ VARS BODY)
           (let ((vars (cadr e)) (body (caddr e)))
             (list '%closure vars body env)))
          ((equal? (car e) 'if)
           (eval_ (if (eval_ (cadr e) env) (caddr e) (cadddr e)) env))
          ((equal? (car e) 'quote) (cadr e))
          ;; Add More Macros Here:
          ;; ((equal? (car e) 'let) xxx)
          ;;((equal? (car e) 'cond) xxx)
          ;;((equal? (car e) 'and) xxx)
          ;((equal? (car e) 'or) xxx)
          (else (let ((eeoe (map (λ (e0) (eval_ e0 env)) e)))
                  (apply_ (car eeoe) (cdr eeoe)))))))
  

Итак, в основном нас просят заполнить пробелы, где находятся комментарии ‘;;’.
Я попытался выполнить часть ‘cond и получил это

 ((equal? (car e) 'cond)
           (env (cdr e) env))
  

Но я понятия не имею, правильно ли это (очень мало знаний о схеме). Любая помощь в выяснении этого будет высоко оценена. Спасибо.

Ответ №1:

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

 (let ((a expr1) (b expr2)) body ...)
  

поддерживается в вашем evaluator уже, если вы изменяете и оцениваете:

 ((lambda (a b) body ...) expr1 expr2)
  

Чтобы заставить вас работать let , работает следующим образом:

 (let ((bindings (cadr e))
      (body (cddr e)))
  (eval_ `((lambda ,(map car bindings) ,@body) ,@(map cadr bindings))))
  

Теперь реальные макросы, которые вы бы ввели в новый тип %closure , чтобы всякий раз, когда вы находите его в качестве operator, вы привязывали символы, а не их оценку, запускали с ним вычислитель, как если бы это была функция, а затем выполняли _eval с результатом. Тогда вместо реализации cond и let вы могли бы просто добавить функцию о том, как переписать ее на то, что вы уже поддерживаете. Таким образом, вы могли бы сделать let вот так:

 ((lambda (let)
   (let ((a expr1) (b expr2))
     (cons a b)))
  (~ (bindings . body) `((lambda ,(map car bindings) ,@body) ,@(map cadr bindings))))
  

Предполагается, что у вас есть quasiquote и map , но это может быть легко реализовано без них с помощью более подробного кода. ~ просто выбирается случайным образом, чтобы быть версией макроса λ . При вычислении это создает, возможно, %mclosure структуру, и вам нужно обрабатывать ее специально, чтобы не оценивать ее аргументы, а оценивать результат. С этого момента вы могли бы поддерживать специальные формы, предварительно определив %mclosure в среде загрузки.