Захват переменных из окружающих абстракций в макросах sicp - PullRequest
1 голос
/ 25 апреля 2020

Я пытаюсь написать функцию более высокого уровня в sicp, которая принимает переменное число функций с одним аргументом и возвращает другую функцию, которая является композицией всех переданных функций. Скажем, функция более высокого уровня называется compose, тогда выполнение (compose f g) должно вернуть мне функцию fog или f(g(x)), где f и g - это некоторые функции с одним аргументом . Я использую конструкцию define-синтаксиса sicp для достижения этой цели, и до сих пор у меня есть следующий код:

(define-syntax apply-to-all-functions
  (syntax-rules ()
    ((apply-to-all-functions f) (f x))
    ((apply-to-all-functions f g) (f (apply-to-all-functions g)))
    ((apply-to-all-functions f . g) (f (apply-to-all-functions . g)))
    ))

(define-syntax compose
  (syntax-rules (x)
    ((compose) (lambda (x) x))
    ((compose g) (lambda (x) (apply-to-all-functions g)))
    ((compose . g) (lambda (x) (apply-to-all-functions . g)))
    ))

В этом коде я пытаюсь захватить x, который связан с lambda в функции / макросе compose, однако, когда я создаю составную функцию и вызываю ее для некоторого значения, я получаю сообщение об ошибке, что идентификатор x не связан. Может кто-нибудь объяснить, как я могу перехватить переменную в вышеупомянутой настройке или каким-либо другим способом решить эту проблему.

Спасибо!:)

1 Ответ

2 голосов
/ 26 апреля 2020

... или каким-либо другим способом решения этой проблемы.

Я не понимаю, почему OP-код пытается использовать макросы для создания более высокого уровня порядок здесь. compose Процедура, которая принимает один или несколько аргументов процедуры, может быть легко написана с использованием точечного синтаксиса для определений процедур.

(define (compose f . fs)
  (if (null? fs)
      (lambda (x) (f x))
      (let ((g (apply compose fs)))
        (lambda (x) (f (g x))))))

Здесь, когда предоставляется только один аргумент, процедура, которая применяет f к один аргумент x возвращается. В противном случае возвращается процедура, которая применяет f к композиции оставшихся аргументов процедуры, а последний аргумент процедуры применяется к одному аргументу x.

Вот демонстрация REPL:

> (define (double x) (* 2 x))
> (define (reciprocal x) (/ 1 x))
> (define (square x) (* x x))
> (define (add1 x) (+ x 1))

> (define doros (compose double reciprocal square))
> (define rodos (compose reciprocal double square))
> (doros 4)
1/8
> (rodos 4)
1/32

> (define dosoaor (compose double square add1 reciprocal))
> (define soroaod (compose square reciprocal add1 double))

> (= (dosoaor 4)
     (double (square (add1 (reciprocal 4)))))
#t
> (dosoaor 4)
25/8
> (= (soroaod 4)
     (square (reciprocal (add1 (double 4)))))
#t
> (soroaod 4)
1/81

Составленная процедура doros должна сначала возвести в квадрат свой аргумент, затем взять обратную величину результата и, наконец, возвратить дважды этот результат. Таким образом, (doros 4) должно быть равно (* 2 (/ 1 (* 4 4))) ==> 1/8, как видно из вышеприведенной демонстрации REPL.

Аналогично, rodos должен сначала возвести в квадрат свой аргумент, затем удвоить результат и, наконец, принять взаимность этого результата. Таким образом, (rodos 4) должно быть равно (/ 1 (* 2 (* 4 4))) ==> 1/32, что соответствует результату REPL.

Тесты, составляющие четыре процедуры, также успешны.

...