Racket: создание потока с помощью макроса вместо функции

В настоящее время я пытаюсь создать поток с помощью макроса, как показано ниже:

(define-syntax create-stream
  (syntax-rules (using starting at with increment )
    [(create-stream name using f starting at i0 with increment delta)
     (letrec 
       ([name (lambda (f current delta) 
                      (cons current (lambda () (name (f (+ current delta) delta)))))])
       (lambda () (name f i0 delta)))
    ]))

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

(create-stream squares using (lambda (x) (* x x)) starting at 5 with increment 2)

Я подозреваю, что при попытке использовать лямбда в макросе он затеняет фактическую лямбда-функцию в Racket. Если это правда, мне интересно, как можно создать поток без использования лямбда, поскольку, насколько я могу судить, где-то должна быть функция для создания указанного потока.

Кроме того, это домашнее задание, поэтому мне нужно использовать макрос. Моя эквивалентная функция для создания потока:

(define create-stream
  (letrec ([name (lambda (f current delta) (cons current (lambda () (name (f (+ current delta) delta)))))])
    (lambda () (name f i0 delta))))

person Chris    schedule 04.03.2021    source источник
comment
вместо того, чтобы удалять часть define name, попробуйте оставить (define name (lambda () (fn i0)) как есть, добавив после нее name, и посмотрите, что произойдет. но вы действительно должны опубликовать новый вопрос со всем этим.   -  person Will Ness    schedule 05.03.2021


Ответы (2)


Я подозреваю, что при попытке использовать лямбда в макросе он затеняет фактическую лямбда-функцию в Racket.

Нет, это неправильно.

Проблема здесь в том, что вы используете f и delta в позициях привязки, в (lambda (f current delta) ...). Это означает, что после расширения (create-stream squares using (lambda (x) (* x x)) starting at 5 with increment 2) вы получите такой код:

(lambda ((lambda (x) (* x x)) current 2) ...)

что, очевидно, является синтаксической ошибкой.

Вы можете убедиться в этом сами, воспользовавшись макростеппером в DrRacket.

Исправление состоит в том, чтобы переименовать идентификаторы во что-то другое. Например.,

(define-syntax create-stream
  (syntax-rules (using starting at with increment )
    [(create-stream name using f starting at i0 with increment delta)
     (letrec 
       ([name (lambda (f* current delta*) 
                      (cons current (lambda () (name (f* (+ current delta*) delta*)))))])
       (lambda () (name f i0 delta)))
    ]))

Это заставит ваш код начать работать, но в вашем коде есть еще несколько ошибок. Поскольку это ваша домашняя работа, я оставлю ее вам.

person Sorawee Porncharoenwase    schedule 04.03.2021
comment
Спасибо, это было весьма полезно. Однако я застрял в новой ошибке, поэтому любые советы будут очень признательны. - person Chris; 05.03.2021
comment
Ну, как вы понимаете проблему? Что вы наделали? - person Sorawee Porncharoenwase; 05.03.2021
comment
Ну, что я сделал, чтобы решить эту проблему на данный момент, так это создать вспомогательную функцию, которая создает поток, а затем мой макрос вызывает ее и назначает имя потока (lambda () (f i0)). Из всего, что я знаю, макросы должны иметь возможность делать это напрямую, но я пока не смог понять, как обернуть это непосредственно в свой макрос (define sname (lambda () (f i0)). - person Chris; 05.03.2021
comment
@Chris, пожалуйста, задайте новый вопрос с минимально воспроизводимым примером, пожалуйста. - person Will Ness; 05.03.2021
comment
@ Крис, ваше редактирование вопроса делает этот ответ недействительным. это не тот способ, которым вопросы должны задаваться на SO. вместо этого вы должны вернуть этот вопрос в его предыдущее состояние и опубликовать новый вопрос со ссылкой на этот вопрос для справки. - person Will Ness; 05.03.2021
comment
Хорошо, я удалил правку. Спасибо, что дали мне знать. - person Chris; 06.03.2021

Ваша текущая проблема по существу сводится к этому (сломанному) коду

(let ((x 0))
    (define y x))

Это не эквивалентно (define y 0) - определение y является локальным для привязки let.

Решение состоит в том, чтобы перевернуть определения и сделать letrec локальным для define:

(define name
    (letrec (... fn definition ...)
        (lambda () (fn i0))))
person molbdnilo    schedule 05.03.2021