Изменяется ли состояние локальной переменной, созданной `let`, во время рекурсивного вызова схемы? - PullRequest
1 голос
/ 24 апреля 2011

Например,

Я хочу проверить, есть ли элемент в списке.Алгоритм прост, давайте сделаем это на C ++

bool element_of( const std::vector<int>& lst, int elem ) {
    for( int i( 0 ), ie = lst.size(); i < ie; ++i ) 
        if( elem == lst[i] )
            return true;
    return false;
}

Поскольку Scheme не позволяет мне использовать один оператор if, я не могу сделать что-то похожее на код C ++ выше.Затем я придумал временную переменную, а именно result.result будет иметь начальное значение #f, затем я рекурсивно вызываю функцию для проверки следующего элемента в списке, т.е. cdr lst ... Итак, мой вопрос, восстанавливает ли переменная, созданная с помощью let, свою начальнуюЗначение каждый раз, когда он вводит новый вызов функции или его значение остается неизменным до последнего вызова?

С другой стороны, используя fold, мое решение было

(define (element-of x lst)
  (fold (lambda (elem result)
          (if (eq? elem x) (or result #t) result)) 
        #f
        lst))

Спасибо

Ответы [ 2 ]

2 голосов
/ 24 апреля 2011

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

(let ((a (func object))
      (b (func object2)))
     (cons a b))

совпадает с написанием

((lambda (a b) (cons a b)) (func object) (func object2))

Таким образом, вы можете видеть, что в синтаксисе Let сначала оцениваются аргументы, а затем тело, а определения a и b используются в локальной среде среды. Поэтому, если вы рекурсивно вызываете Let, каждый раз, когда вы вводите тело вызова Let, вы оцениваете тело в новой среде (потому что тело находится внутри недавно определенной лямбды), а определение аргументов определяется в локальной Let области видимости будут другими (они на самом деле являются новыми переменными во вложенной среде, настроенной новой лямбдой, а не просто переменными, которые были видоизменены или «переопределены», как вы могли бы найти в цикле C ++).

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

Надеюсь, это поможет,

Jason

1 голос
/ 24 апреля 2011

let всегда повторно инициализирует переменные;это очевидно, поскольку вы всегда должны указывать новые значения привязки.Например,

(let ((a 42))
  ...)

Внутри ..., a всегда начинается с 42, всегда.Он не «сохраняет» значения из предыдущих вызовов.


Кстати, я думаю, вы хотели написать (or result (equal? elem x)) вместо (if (eq? elem x) (or result #t) result).: -)

(or result (equal? elem x)) переводится в следующий код C ++:

return result || elem == x;

(при условии, что оператор == был перегружен для выполнения того, что делает equal?, конечно.) Преимущество этого заключается в том, что если result уже верно, дальнейшие сравнения не выполняются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...