Упорядочение вложенных let и lambda в схеме - PullRequest
3 голосов
/ 02 апреля 2011

В чем разница между двумя функциями в схеме, одна из которых определена следующим образом & mdash;

(define doSomething
    (lambda (x)
          (let (f (100))
               (f x))))

и тому подобное? & Mdash;

(define doSomething
          (let (f (100))
            (lambda (x) 
               (f x)))) 

Другими словами, какое это имеет значение, если lambda находится перед let или после него?

Ответы [ 3 ]

5 голосов
/ 02 апреля 2011

Как указывает Крис, код не будет работать. Поэтому я собираюсь использовать новый пример для объяснения идиомы let over lambda.

Когда вы окружаете lambda форму с let, как это:

 (let ((x 0))
   (lambda ()
     ; body
     ))

Код в теле lambda может получить доступ (включая изменение) к x даже после окончания let и возврата новой функции. Это один из примеров создания «замыкания», который поначалу сложно понять.

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

A double функция, которая подсчитывает, сколько раз она была вызвана:

(define double
  (let ((count 0)) ; closed over variable
    (lambda (x)
      (if (eq? x 'count)
          count
          (begin 
            (set! count (+ count 1)) ; incr the count variable introduced by let
            (+ x x))))))

> (double 1)
2
> (double 1)
2
> (double 1)
2
> (double 'count) ; ask the double function how many times it's been called
3
> 

Этот пример действительно любезен Пол Грэм (http://www.paulgraham.com/accgen.html)

(define make-accumulator
  (lambda ()
    (let ((x 0))
      (lambda (i)
        (set! x (+ x i)) ; incr x by i
        x))))

> (define acc (make-accumulator))
> (acc 1)
1
> (acc 1)
2
> (acc 1)
3
> (acc 1)
4
> 

Каждый раз, когда acc вызывается с 1, значение, которое он возвращает, отличается.

Для примеров «объектов» найдите «объекты и замыкания» или просто прочитайте соответствующие разделы SICP: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#%_sec_3.1

5 голосов
/ 02 апреля 2011

Ваш код не будет работать. : -)

Я предполагаю, что вы имеете в виду следующее:

(lambda (x)
  (let ((f 100))
    (+ f x)))

и

(let ((f 100))
  (lambda (x)
    (+ f x)))

В обоих случаях вы получите возвращенный аргумент плюс 100.

Однако, главное отличие (игнорирование технических аспектов того, как let является просто синтаксическим сахаром над lambda) заключается в том, что во второй версии f является свободной переменной. Скажем, мы делаем это:

(let ((f 100))
  (list (lambda (x)
          (+ f x))
        (lambda (x)
          (set! f x))))

Возвращает список с двумя лямбдами: первая из них такая же, как ранее, а вторая, позволяющая изменить значение f. Обе лямбды обращаются к одному и тому же f, поэтому запуск сеттера будет влиять на последующие вызовы первой лямбды.

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

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

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