Jaka jest różnica między programem a kontynuacją a generatorem?
generator
continuations
coroutine
Mehdi Asgari
źródło
źródło
Odpowiedzi:
Zacznę od generatorów, ponieważ są one najprostszym przypadkiem. Jak wspomniał @zvolkov, są to funkcje / obiekty, które można wielokrotnie wywoływać bez zwracania, ale po wywołaniu zwracają (zwracają) wartość, a następnie zawieszają ich wykonanie. Kiedy zostaną ponownie wezwani, zaczną od miejsca, w którym ostatnio zawiesili wykonanie, i zrobią swoje.
Generator jest zasadniczo ograniczonym (asymetrycznym) programem. Różnica między programem a generatorem polega na tym, że program może przyjmować argumenty po jego pierwotnym wywołaniu, podczas gdy generator nie może.
Trochę trudno jest wymyślić trywialny przykład użycia coroutines, ale oto moja najlepsza próba. Weźmy ten (zmyślony) kod Pythona jako przykład.
Przykładem zastosowania koreutynów są leksery i parsery. Bez koreprogramów w języku lub w jakiś sposób emulowanych, leksowanie i parsowanie kodu muszą być mieszane razem, mimo że są to tak naprawdę dwie odrębne kwestie. Ale używając coroutine, możesz oddzielić kod leksykalny i parsujący.
(Mam zamiar przeoczyć różnicę między symetrycznymi i asymetrycznymi korutynami. Wystarczy powiedzieć, że są równoważne, można konwertować z jednego do drugiego, a asymetryczne korutyny - które są najbardziej podobne do generatorów - są łatwiejsze do zrozumienia. Opisywałem, jak można zaimplementować asymetryczne programy w Pythonie).
Kontynuacje to właściwie całkiem proste bestie. Wszystkie one są funkcjami reprezentującymi inny punkt w programie, który, jeśli go wywołasz, spowoduje automatyczne przejście do punktu, który reprezentuje funkcja. Używasz ich bardzo ograniczonych wersji każdego dnia, nawet nie zdając sobie z tego sprawy. Na przykład wyjątki można traktować jako swego rodzaju kontynuację na odwrót. Dam ci przykład kontynuacji oparty na pseudokodzie w Pythonie.
Powiedzmy, że Python ma wywołaną funkcję
callcc()
, która pobiera dwa argumenty, pierwszy to funkcja, a drugi to lista argumentów, z którymi można ją wywołać. Jedynym ograniczeniem tej funkcji byłoby to, że ostatnim argumentem, który przyjmuje, będzie funkcja (która będzie naszą obecną kontynuacją).To co by się stało,
callcc()
to z kolei wywołaniefoo()
z bieżącą kontynuacją (cc
), czyli odniesieniem do punktu w programie, w którymcallcc()
został wywołany. Kiedyfoo()
wywołuje bieżącą kontynuację, jest to w zasadzie to samo, cocallcc()
polecenie powrotu z wartością, z którą wywołujesz bieżącą kontynuację, a kiedy to robi, cofa stos do miejsca, w którym bieżąca kontynuacja została utworzona, tj. Kiedy zadzwoniłeścallcc()
.Rezultatem tego wszystkiego byłby wydruk naszego hipotetycznego wariantu Pythona
'42'
.Mam nadzieję, że to pomoże i jestem pewien, że moje wyjaśnienie można znacznie poprawić!
źródło
Program jest jedną z kilku procedur, które wykonują swoją pracę na zmianę, a następnie zatrzymują się, aby przekazać kontrolę innym programom w grupie.
Kontynuacja to „wskaźnik do funkcji” przekazywany do jakiejś procedury do wykonania („kontynuacja z”) po zakończeniu tej procedury.
Generator (w .NET) to konstrukcja języka, która może wypluć wartość, „wstrzymać” wykonanie metody, a następnie przejść od tego samego punktu, gdy zostanie wyświetlony monit o podanie następnej wartości.
źródło
W nowszej wersji Pythona możesz wysyłać wartości do Generatorów za pomocą
generator.send()
, co sprawia, że Generatory Pythona są efektywnie dopasowane.Główna różnica między generatorem Pythona a innym generatorem, powiedzmy Greenlet, polega na tym, że w Pythonie
yield value
możesz tylko wrócić do dzwoniącego. Będąc w greenlet,target.switch(value)
może zabrać cię do określonego programu docelowego i podać wartość, przy którejtarget
nadal będzie działać.źródło
yield
wywołania muszą mieć tę samą funkcję, która nazywa się „generatorem”. Nie możeszyield
z podfunkcji, dlatego Python nazywa się semi-coroutines , podczas gdy Lua ma asymetryczne coroutines . (Są propozycje rozmnażania plonów, ale myślę, że te tylko mętną wodę.)