Функция оценки лямбда не может быть использована для определения новой функции в области видимости
В схеме вы можете определить функции, которые возвращают лямбда-выражение и использовать их для определения новых функций. Например, вы можете написать этот код
(define (pow-iter base exp r)
(if (= exp 1)
r
(pow-iter base (- exp 1) (* base r))))
(define (pow exp)
(lambda (base)
(pow-iter base exp base)))
(define cubic (pow 3))
(cubic 2)
У нас есть функция pow
который принимает показатель степени в качестве аргумента и вычисляет лямбда-функцию, которая вычисляет n-ую степень данного основания.
Однако, если мы поместим это в такую область:
(define (do-cubic x)
(define (pow-iter base exp r)
(if (= exp 1)
r
(pow-iter base (- exp 1) (* base r))))
(define (pow exp)
(lambda (base)
(pow-iter base exp base)))
(define cubic (pow 3))
(cubic x))
(do-cubic 2)
Я получаю ошибку
Pow: не определено; нельзя использовать до инициализации
Почему возникает эта ошибка и есть ли способ ее исправить, не меняя логику программы?
1 ответ
Эта программа вызывает ту же ошибку:
#lang r5rs
(let ()
(define (foo x) (lambda (y) (+ 42 x)))
(define bar (foo 1))
(bar 2))
Output:
foo: undefined;
cannot use before initialization
Причина, по которой вы получаете ошибку, состоит в том, что "внутренние определения" переписываются в letrec
В выражении все привязки действуют, пока их начальные значения вычисляются, что позволяет взаимно рекурсивные определения.
(letrec ((foo (lambda (x) (lambda (y) (+ 42 x))))
(bar (foo 1)))
(bar 2))
В R5RS выражения инициализации оцениваются в неуказанном порядке. Это означает, что в первом фрагменте выше возможно (define bar (foo 1))
подлежит оценке до (define (foo x) ...)
, Другими словами, значение foo
нужно раньше foo
были инициализированы.
В ракетке (#lang racket
) внутренние определения использования letrec*
-семантика (т.е. выражения инициализации оцениваются в порядке их появления в коде. Таким образом, программа работает без ошибок.
Обратите внимание также, что letrec
в #lang racket
соответствует чему letrec*
делает в "R5RS"-реализации.
Для получения дополнительной информации о letrec
против letrec*
см. введение http://www.cs.indiana.edu/~dyb/pubs/letrec-reloaded.pdf