Схема: почему этот результат при переопределении предопределенного оператора?

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

Здесь код:

(define (f a b) 4)

(define (show)
  (display (+ 2 2)) (display ",") (display (f 2 2)) (newline))

(show)
; guile & mit-scheme: "4,4"

(define (+ a b) 5)
(define (f a b) 5)

(show)
; mit-scheme: "5,5"
; guile: "4,5" - this "4" is the unexpected result

(define (show)
  (display (+ 2 2)) (display ",") (display (f 2 2)) (newline))

(show)
; guile & mit-scheme: "5,5"

В guile функция show использует предопределенное определение + даже после того, как я ее переопределил, хотя он использует новое определение f. Мне нужно переопределить show, чтобы узнать, что нового определения +. В mit-scheme оба новых определения сразу распознаются, что я и ожидал. Кроме того, любые дальнейшие определения + мгновенно распознаются обоими интерпретаторами без необходимости переопределять show.

Что происходит за кулисами в guile, чтобы связать ссылки с этими переопределенными операторами по-разному?

И почему разница между двумя переводчиками?

Ответ 1

Похоже, что Guile ошибочно полагает, что никто не настолько сумасшедший, чтобы переопределить + и делает оптимизацию складывания (+ 2 2) => 4, делая (display (+ 2 2)) стать (display 4). Это объясняет, почему вам нужно переопределить show, чтобы отразить ваш новый +.

В самом деле, если вы сначала сделаете (define (+ a b) 4) в самой верхней части своей программы, Guile не будет делать эту оптимизацию, и вы получите 4,4 и 5,5 так же, как MIT Scheme.

Изменить: На самом деле, похоже, что Guile оптимизирует + для ссылки на собственную конструкцию +, что означает, что даже если вы не используете константы (без постоянной сгибания), вы будете по-прежнему не может переопределить +.