Реализация встроенной функции схемы begin () с использованием самой схемы, один и тот же код ведет себя по-разному в MIT-SCHEME и Racket?

Я читаю стандарт схемы r5rs и обнаруживаю, что begin () на самом деле является синтаксисом библиотеки, что означает, что он может быть определен самой схемой, а стандарт дает реализацию в конце стандарта.

Я последовал за r5rs, чтобы реализовать begin (), используя синтаксис определения, как показано ниже:

(define-syntax mybegin
  (syntax-rules ()
                ((mybegin expr) expr)
                ((mybegin expr1 expr2 ...)
                 (let ((x expr1))
                   (mybegin expr2 ...)))))

а затем я попытался реализовать это с помощью функции, вот мой код:

(define begin-func
  (lambda (expr1 expr2)
    ((lambda (x) expr2) expr1)))

вот мои тестовые примеры:

(define x 3)
(define y 3)
(mybegin
  (set! x 4)
  (set! x 5))
(begin-func
  (set! y 4)
  (set! y 5))

Я запустил свой код в MIT-SCHEME и Racket, используя схему #lang, x равно 5 как в MIT-SCHEME, так и в Racket, однако y равно 4 в MIT-SCHEME, но 5 в Racket

Вот мой вопрос:

  1. Верно ли, что мы действительно могли бы реализовать begin (), используя чисто функциональную схему?
  2. Что-то не так в моем коде, как в коде, использующем макрос, так и в коде, использующем функцию?
  3. почему один и тот же код ведет себя по-разному в MIT-SCHEME и Racket?

person Alaya    schedule 11.08.2014    source источник


Ответы (1)


begin - это специальная форма, оценивающая каждый элемент по порядку и до самого последнего выражения. Вам никогда не понадобится begin в чисто функциональной Схеме, но можно получить функциональность, аналогичную begin, функционально в Схеме, которая не имеет begin в качестве специальной формы или встроена в lambda формы или родственников. Это только одно исключение, и это define внутри него. define в начале верхнего уровня будет определяться глобально, в то время как имитация будет использовать процедуры для упорядочивания оценки, а define тогда станет только локальной привязкой, которая умирает, когда процедура выходит за пределы области действия.

begin должен быть определен как синтаксис, потому что если вы создадите такую ​​процедуру, как:

(define (mybegin . args)
  ...)

Все аргументы при вызове mybegin будут оцениваться в порядке, зависящем от реализации. В отчете говорится, что оценка должна быть последовательной, чтобы одна реализация не получала 4 один раз, а 5 - другой, но вы будете видеть, как одна из них происходит каждый раз для одной и той же процедуры. Не гарантируется, что оценка будет происходить в одном и том же порядке и для двух разных процедур, но многие реализации Scheme обычно делают это в одном и том же порядке.

Racket всегда оценивает аргументы по порядку, что нормально, потому что в отчете говорится, что вы можете делать это, как хотите, в то время как MIT, по крайней мере, иногда оценивает в обратном порядке.

person Sylwester    schedule 11.08.2014
comment
@benrudgers Нет такой вещи, как чисто функциональная Scheme, но вы можете программировать Scheme чисто функциональным способом. Он упоминает функциональную схему в своем первом вопросе и избегает использования явных begin в let и, скорее, вложенных let форм, как если бы let работал только с хвостовыми вызовами. Это делает этот вопрос более интересным, поскольку показывает, что мы можем сделать функциональные языки менее функциональными с помощью макросов. - person Sylwester; 11.08.2014