2016-04-12 1 views
1

Это курс SICP для раздела экологической модели:Почему (c1) возвращает 1, 2, 3 ect .. и не # <procedure: ... make_counter.rkt: 8: 5>?

(define make-counter 
    (lambda (n)  
    (lambda() (set! n (+ n 1)) 
     n)))  

Ниже, переводчик говорит, что (make-counter 0) процедура:

> (make-counter 0) 
#<procedure:...make_counter.rkt:8:5> 

Ниже я определяю c1, являющийся (make-counter 0).

(define c1 (make-counter 0) 

Ниже, где я запутался, по причине возвращает счетчик значения вместо "procedure".

>(c1) 
1 
> (c1) 
2 
> (c1) 
3 

Мой мыслительный процесс является то, что если указывает на процедуру, (make-counter), то должен возвращать "procedure:...make_counter.rkt:8:5".

Потому что процедура -> процедура.

Я вижу, что должно произойти, я просто смущен, концептуально, как и почему.

+0

Эти ответы помогают мне проверить мои мысли. Один кусок головоломки - как –

+0

Пожалуйста, не забывайте: используйте полезные ответы и отметьте один как решение, чтобы оно было закрыто. Или переформулируйте вопрос. –

+0

Наконец, я не понимаю, почему (c1) возвращает счетчик. Теперь его (счетчик 0). Работая вручную, я не понимаю, почему n не возвращается. Может кто-то объяснить это мне? –

ответ

2

Что вы хотите сказать? Вы сомневаетесь, что это работает, как предполагает название, или вы не понимаете, как это происходит?

Первый может быть проверен в течение 30 секунд, я ответить на второй:

макияж счетчиком является процедурой, которая принимает один аргумент. Теперь посмотрите на код еще раз: что он возвращается? Процедура с 0 аргументами.

Таким образом, выполнение будет возвращать цифры от 1 до (если начинаться с 0).

Для полноты:

Gambit v4.8.1 

> (define make-counter 
    (lambda (n)  
    (lambda() (set! n (+ n 1)) 
     n)))  
> (define c1 (make-counter 0)) 
> (c1) 
1 
> (c1) 
2 
> (c1) 
3 
> 

Добавление после вопроса редактирования:

c1 является процедура, но является процедура приложения, что вы бы назвали «вызовом процедуры» в другом программировании Мир.

> c1 
#<procedure #2 c1> 
> (c1) 
1 

BTW хороший фрагмент функционального кода, если вы поняли это, вы будете смотреть на программирование по-разному.

Больше вопросов через комментарий:

Теперь его (сделать счетчик 0). Работая этим вручную, я не понимаю , почему n не возвращается.

Ответ тот же мы дали вам о c1 и :

make-counter возвращается lambda() и п возвращается только, если вы звоните лямбда. Функции (в схеме: процедуры, лямбда) - это значения, которые могут быть переданы, принцип функционального программирования. Вы должны называть их (правильный термин: применить) получить результат процедуры.

Теперь скажите мне: как вы называете процедуру в схеме?

больше редактирует:

Ладно, мы называем процедуру в схеме, заключив его в круглых скобках.

Теперь скажите мне: Каков шаг замещения для ?

+0

Я просто полностью отредактировал свой вопрос. –

+0

Да, его начало иметь смысл для моего толстого черепа! Вызов функции: Включение функции в скобки с необходимыми аргументами. Это будет оценивать процедуру и применять к ней аргументы. В этом случае, поскольку это модель среды, она просто не использует правило подстановки, верно? Кажется, нужен дополнительный шаг с внутренней лямбдой, инкапсулирует n-переменную, которая заставляет ее быть несвязанной. (Make-counter 0) оценивает и применяет от 0 до n, но возвращает процедуру(), а не новое значение n. Я должен (c1 (make-counter 0)) вернуть новый n. Это правильно? –

+0

@TrieuNguyen О приложении: справа, но вторая часть false, c1 - это лямбда, которая не принимает параметры. Точка c1 выполняется в среде make-counter, поэтому переменная n в свободном состоянии c1. Возможно, вы должны позволить этому вопросу отдохнуть и созреть в течение нескольких дней, а затем переосмыслить его. –

2

Мой процесс мышления состоит в том, что если (c1) указывает на процедуру (счетчик), то (c1) должен возвращать «procedure: ... make_counter.rkt: 8: 5».

Это неправильно.

Что здесь происходит, так это то, что c1 «указывает на процедуру», как вы говорите (на самом деле это имя связано с процедурой).

Вы должны помнить, что на схеме форма (f e1 e2 ... en) является способом вызова процедуру, f, передавая ему значение выражений e1 e2 ... en.

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

+0

Да, я вижу, что моя первая проблема - синтаксис, в котором я делаю первую ошибку. –

1

Вы

(define make-counter 
    (lambda (n)  
    (lambda() (set! n (+ n 1)) 
     n))) 

так оценки make-counter

возвращается

(lambda (n)  
    (lambda() (set! n (+ n 1)) 
     n)) 

и оценки (make-counter 0) просто заменяет make-counter в этот призыв с его значением, и продолжается, как

((lambda (n)  
    (lambda() (set! n (+ n 1)) 
     n)) 
    0) 
=> 
(let ((n 0))  
    (lambda() (set! n (+ n 1)) 
     n)) 

поэтому объект укупорочное создается и возвращается,

=> 
(closure {environment1: ((n 0))}  ; its own binding for `n` 
    (lambda() (set! n (+ n 1)) 
     n)) 

поэтому после (define c1 (make-counter 0)) это замыкание значение c1.

Оценка c1 возвращает свое значение, процедура (закрытие) выше. Его напечатанное представление зависит от реализации (показывая, например, #<procedure> или что-то подобное).

Оценка вызовов эту процедуру,

(c1) 
=> 
((closure {environment1: ((n 0))}  ; its own binding for `n` 
    (lambda() (set! n (+ n 1)) 
     n))) 
=> 
(under {environment1: ((n 0))} 
    ( (lambda() (set! n (+ n 1)) 
     n))) 

Вызов ((lambda() ...)) без каких-либо аргументов, просто оценивает свое тело, не создавая новую среду, так как список параметров пуст, и нет никаких аргументов:

=> 
(under {environment1: ((n 0))} 
    (set! n (+ n 1))    ; perform this first 
    n) 
=> 
(under {environment1: ((n 1))} ; <--- altered binding for `n`! 
    n)       ; now evaluate this and return its value 
=> 
1 

и оставляет измененenvironment1 на своем следе. Когда эта процедура (закрытие) будет вызвана снова, , ее окружение теперь будет содержать ((n 1)) и поэтому будет изменено на ((n 2)) и т. Д.

+0

Объяснение дополнительных правил действительно помогает моему пониманию/беспокойству. Он по-прежнему использует правило подстановки, но поскольку он создает среду, интерпретатор должен выполнить несколько дополнительных шагов, за исключением того, что мне не нужно явно писать это. Это верно? Есть немного больше, что под капотом (как вы объяснили). Разве это попадет в категорию специальной формы или синтаксического сахара в том смысле, что нам действительно не нужно явно запускать строки кода, вместо этого мне просто нужно определить make-counter и c1? –

+0

Это позволяет предположить, что Scheme действительно создает реальные объекты в памяти, построенные из пар и символов - т. Е. Символические выражения - см. Http://www-formal.stanford.edu/jmc/recursive.ps. Изучение этой статьи (и главы mceval SICP) действительно помогло мне. См. Также, если [этот мой ответ] (http://stackoverflow.com/a/34910496/849891) разъясняет вещи (если нет, не вкладывайте в него слишком много усилий, идите с классикой). - Таким образом, этот процесс оценки очень конкретный и явный, он фактически манипулирует этими помеченными списками в памяти. Когда это будет понято, мы можем перейти к более сложным способам интерпретации/компиляции –

+0

.... - Нет, особых форм там нет. Когда я пишу '(в разделе {environment1: ...' это как псевдокод, но он может быть реализован как фактические помеченные списки в памяти (а «environment1» - это имя такого объекта в памяти, с определенным адресом памяти - список имен переменных и их значений, т. е. окружающая среда). См. мой другой ответ, который я упомянул, который переписывает код из этой статьи в некоторых более читаемых (для меня) псевдокодах (исправление: код из упомянутой там книги, а не бумага, но они близки). Изучите код из статьи. –

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