На схеме цель (let ((cdr cdr))

Недавно я изучал Scheme и сталкивался с функцией, которая определяется следующим образом:

(define remove! 
    (let ((null? null?)
          (cdr cdr)
          (eq? eq?))
     (lambda ... function that uses null?, cdr, eq? ...)

Какова цель привязки нулевого значения? to null? или cdr в cdr, когда они встроены в функции, доступные в определении функции без блока let?

Ответы

Ответ 1

В простой схеме R5RS нет модульной системы - только для верхнего уровня. Кроме того, менталитет состоит в том, что все может быть изменено, поэтому вы можете "настроить" язык любым способом. Но без модульной системы это не работает. Например, я пишу

(define (sub1 x) (- x 1))

в библиотеке, которую вы загружаете, и теперь вы можете переопределить -:

(define - +) ; either this
(set! - +)   ; or this

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

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

(define sub1 (let ((- -)) (lambda (x) (- x 1))))

Теперь все будет работать "более хорошо", так как вы не можете изменить значение моей функции sub1, изменив -. (За исключением... если вы измените его, прежде чем загружать мою библиотеку...)

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

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

Ответ 2

Это оптимизация скорости. Локальный доступ к переменной обычно быстрее глобальных переменных.