2016-03-20 2 views
1

Я имеющий трудное время, чтобы понять масштабы следующего кода:Трудность в понимании пусть и использование лямбды на схеме

(define (create-counter (x 1)) 
    (let ([count 0]) 
    (lambda() 
     (let ([temp count]) 
     (set! count (+ x count)) temp)))) 

, если я использую: однако

(let ((c (create-counter))) (+ (c) (c) (c) (c))) 

код работает, если я пытался с:

(+ (create-counter)(create-counter)(create-counter)(create-counter)) 

Это не работает и дает мне 0. Может кто-то, пожалуйста, помогите мне разобраться в этом полностью ? если возможно, пожалуйста, сравните с другим языком, как C/C++, мне будет легче поймать это. Спасибо

+1

Вы имеете в виду '(+ ((создание-счетчик)) ((создать счетчик)) ...)', верно? С одним набором круглых скобок вокруг 'create-counter' я ожидал бы ошибку, потому что вы пытаетесь добавить lambdas. – sepp2k

+0

Когда вы говорите «не работает и дает мне 0» ... что вы ожидаете от последнего выражения? – uselpa

+0

@ sepp2k: если только 1 круглые скобки, функция возвращает определение процедуры am i correct? – kp2349

ответ

2
(define (create-counter (x 1)) 
(let ([count 0]) 
    (lambda() 
    (let ([temp count]) 
    (set! count (+ x count)) temp)))) 

Переводит на:

auto create_counter(int x=1){ 
    int count=0; 
    return [x,count]()mutable{ 
    int r=count; 
    count+=x; 
    return r; 
    }; 
} 

Простой C++ 14 функция, возвращающая объект закрытия.

Когда вы сделаете это:

(let ((c (create-counter))) (+ (c) (c) (c) (c))) 

Это:

auto c = create_counter(); 
auto r = c()+c()+c()+c(); 
return r; 

Это создает один счетчик, а затем запускает его в 4 раза, возвращая 0 1 2 3 и добавление 6.

В этом случае:

(+ ((create-counter))((create-counter))((create-counter))((create-counter))) 

Это:

auto r = create_counter()()+create_counter()()+create_counter()()+create_counter()(); 
return r; 

Который создает 4 счетчика и запускает их каждый раз. При первом запуске счетчика вы получаете 0. Таким образом, это добавляет 0.

Объект закрытия имеет состояние. Он возвращает большее число каждый раз, когда вы его вызываете.

Теперь вы, возможно, не знакомы с C++ 11/14 lamnda.

auto create_counter(int x=1){ 
    int count=0; 
    return [x,count]()mutable{ 
    int r=count; 
    count+=x; 
    return r; 
    }; 
} 

Является

struct counter { 
    int x,count; 
    int operator()(){ 
    int r=count; 
    count+=x; 
    return r; 
    }; 
}; 
counter create_counter(int x=1){ 
    return {x,0}; 
} 

с некоторыми синтаксическими.

Я исправил то, что кажется синтаксической ошибкой в ​​исходном коде. Я не эксперт, поэтому, возможно, я ошибся.

Как и в сторону, краток создать счетчик выглядит следующим образом:

auto create_counter(int x=1){ 
    return [=,count=0]()mutable{ 
    int r=count; 
    count+=x; 
    return r; 
    }; 
} 
+0

очень тщательный описание. Я лучше понимаю эту идею. – kp2349

2

Когда вы вызываете «create-counter», он создает счетчик, а затем возвращает процедуру, которая ссылается на этот конкретный счетчик. Когда вы вызываете «create-counter» четыре раза, вы создаете четыре отдельных счетчика; каждая процедура относится к собственному счетчику. Когда вы вызываете «create-counter» один раз, а затем результирующую процедуру четыре раза, он создает только один счетчик и увеличивает его четыре раза.

Сравнивать это с C очень сложно, поскольку C и C++ довольно слабы в области замыканий; вернуть функцию, определенную внутри другой функции, непросто.

Ближайшим аналогом может быть объект «counter» в C++; подумайте о «create-counter» в качестве конструктора для объекта, содержащего единственное целое число, и результирующую процедуру как метод «increment», который увеличивает счетчик, содержащийся в этом объекте. Во втором примере вы создаете четыре разных объекта, где в первом примере вы создаете один объект и четыре раза вызываете его метод «increment».

+0

Закрытие имеет поддержку синтаксиса, поскольку C++ 11, 5 лет назад, что упрощает их возврат. – Yakk

+0

@ Yakk C++ 11 lambdas не похожи на закрытие схемы. В схеме местоположения имеют «неограниченную протяженность», и это невозможно, чтобы вызвать оборванную ссылку. Если в C++ lambdas вы должны сказать, является ли ссылка свободной переменной ссылкой или значением; первый может вызвать оборванные ссылки. –

+0

@chris Это просто объект жизни. В C++ автоматические переменные хранилища определены как недопустимые для доступа после определенного момента: просто изменение состояния. Все добавления схемы принудительно освобождают распределение хранилища и накладные расходы на сбор мусора: оба они являются необязательными в C++. (Полный стиль gc с меткой и разверткой сложный на C++, но выполнимый). Если вам не требуется разделяемое состояние, вы можете просто принять значение. Независимо от того, что в случае OP нет * ничего, что простая C++ лямбда не обрабатывает изменчивый захват по значению, как я продемонстрировал в своем сообщении. – Yakk

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

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