2009-03-17 9 views
8

Я пишу интерпретатор Scheme, и я столкнулся с действительным утверждением, пусть такие, как:Лисп оценки позволяют заявления

;; should print 7 
(let ((a 4) (b 3)) 
    (let ((a (* a a)) 
      (b (* b b))) 
     (+ a b) 
     (- a b))) 

Мой переводчик не реализует только чисто функциональное подмножество схемы, так что будет не побочные эффекты, такие как set !. В чисто функциональном языке, почему вы допускаете несколько выражений внутри оператора let, например, выше?

И в письменной форме мой переводчик, есть ли какая-то причина, по которой я должен оценивать что-либо, кроме последнего выражения в let? Похоже, что они никогда не повлияют на результат оценки последнего утверждения.

ответ

2

Вы правы (почти): если вы реализуете чисто функциональное подмножество схемы (т.е. не set!, set-car!, set-cdr!), то любое выражение, но последнее в let будет иметь их возвращаемое значение выброшено, и так как вы гарантированно не будете иметь побочных эффектов, нет никакой опасности молчаливо игнорировать их.

Однако есть один небольшой случай, вам необходимо рассмотреть, и что, когда предыдущие выражения define s:

(let ((x 3)) 
    (define y 4) 
    (+ x y)) 

Это как юридические, так и функционально. Однако есть хорошие новости - внутри блока (например, let) вы должны иметь все свои define s наверху. Как и в, это не считается правовой схемой:

(let ((x 3)) 
    (+ 2 3) 
    (define y 4) 
    (+ x y)) 

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

Редактировать:antti.huima делает отличную точку зрения о вызове/куб.Если вы собираетесь включить продолжение в свою реализацию, вы действительно не можете сделать много предположений о том, когда все будет оценено.

1

ОК, let просто создает привязку, как define. Там нет ничего, что меняет связанную переменную вроде set!. Итак, подумайте о том, что из области ваших имен: a of '(+ a b) the same as the a` вы обязаны 4? (Подсказка: Нет.)

Реальная точкой здесь является то, что вам нужно правильно вести себя даже в hinky случаев так: обзорная и обязательные правила просты и четко определены, и делать что-то подобное, что выглядит смущает, является лишь следствием их. Это удобно, потому что, имея локальные привязки с лексической привязкой с let, вы можете писать более четкие программы, даже если есть извращенные боковые случаи.

обновление О, я остановился на точке. Вы правы, что вызов (+ a b) не имеет долгосрочного эффекта, но тогда вы не можете в общем случае предположить, что это правда, и вы не можете определить, верно ли это, если изучить текст программы там один. (Рассмотрите: там могут быть другие функции вместо «+».) Однако, если вы считаете, что получите правильный результат, не оценивая различные статьи let, вы не понимаете, что он пытается делаю еще.

6

На самом деле вы не можете «отбросить» все, кроме последнего оператора, потому что предыдущие утверждения могут быть не завершающими. Например:

(define (func) (func)) 

(let() 
    (func) ;; does not return 
    1) 

Здесь, если вы оставите (func) невычисленного, вы получите неверный результат (который равен 1), в то время как вы должны получить не-прекращения вычислений.

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

(call-with-current-continuation 
    (lambda (ret) 
    (let() 
     (ret 3) 
     4))) 

который будет возвращать и не 4. Это еще чисто функциональным.

Примечание Кстати, что (let() x y z) эквивалентно форме одного заявления (let() (begin x y z)) поэтому реальный вопрос, если вам нужно begin :)

 Смежные вопросы

  • Нет связанных вопросов^_^