Kontynuacja () – abstrakcyjny konstrukt programistyczny służący do sterowania przepływem programu. Każdy język programowania posiada kontynuacje, ponieważ tak właśnie działają języki programowania, lecz tylko niektóre dają do nich bezpośredni dostęp. W skrócie można powiedzieć, że kontynuacja to następna instrukcja, która ma zostać wykonana, gdy skończy się wykonywać aktualna instrukcja. Gdy język umożliwia bezpośredni dostęp do kontynuacji, możliwy jest powrót do miejsca w którym kontynuacja została utworzona. Dzięki kontynuacjom można zaimplementować takie konstrukcje programistyczne jak wyjątki, współprogramy, czy generatory.

Jednym z języków programowania, który daje bezpośredni dostęp do kontynuacji jest język Scheme. W tym języku kontynuacje są typem pierwszoklasowym. Według specyfikacji języka, powinny się zachowywać dokładnie tak jak funkcje.

W języku Scheme, aby pozyskać obiekt kontynuacji używa się konstrukcji call-with-current-continuation (lub skrótu call/cc). Jest to tzw. przechwycenie kontynuacji (). Mając dostęp do obiektu kontynuacji możliwy jest powrót i kontynuowanie działania programu w miejscu, w którym kontynuacja została przechwycona.

Istnieje także sposób użycia kontynuacji w językach funkcyjnych, które nie dają bezpośredniego dostępu do kontynuacji dzięki tzw. stylowi przekazywania kontynuacji (). Jest to specjalny sposób pisania programów, w którym wszystkie kontynuacje są jawne, utworzone dzięki zwykłym funkcjom.

Przykład Najprostszym przykładem użycia kontynuacji może być nieskończona pętla:

(let () (define k (call/cc (lambda (cc) cc))) (display "Wikipedia") (newline) (k k))

W tym przykładzie tworzymy pusty zasięg i wewnątrz przypisujemy do zmiennej k kontynuacje. Gdy wywołamy kontynuację, kod przeskoczy do miejsca, w którym zostaje przypisana wartość do zmiennej k. Gdy przekażemy (k 10), zostanie wywołane (define k 10), ponieważ w tym momencie kontynuacja została przypisana do zmiennej k. Natomiast, gdy wywołamy (k k), program przeskoczy na górę i wywoła (define k k) (przy czym pierwsze k to identyfikator a drugie to wartość kontynuacji). Dzięki temu mamy nieskończoną pętlę.

Innym przykładem może być tzw. wczesne wyjście (). Język Scheme nie pojada instrukcji return znanej z innych języków programowania, ale dzięki kontynuacjom istnieje możliwość wczesnego wyjścia.

(define (find item lst) (call-with-current-continuation (lambda (return) (for-each (lambda (x) (if (equal? x item) (return x)) (display x) (newline)) lst))))

(let ((result (find 'x '(a b d x y z f)))) (display "wynik: ") (display result) (newline))

Procedura for-each iteruje po wszystkich elementach listy, natomiast funkcja find wywołuje kontynuację return, która wychodzi z funkcji i nie kontynuuje przetwarzania kolejnych elementów listy, gdy zostanie znaleziony szukany element.

Kontynuacje w połączeniu z makrami umożliwiają tworzenie nowych konstrukcji programistycznych.

Przykład CPS Poniżej znajduje się przykład wykorzystywania stylu przekazywania kontynuacji w języku JavaScript:

function silnia(n, cc) { if (n == 0) { cc(1); } else { silnia(n-1, function(t0) { cc(n * t0); });

silnia(10, function(wynik) { console.log(wynik); // 3628800 });

W definicji funkcji nie została użyta instrukcja sterująca return, tylko kontynuacja w formie funkcji przekazana jako drugi argument.

Przypisy

Linki zewnętrzne

Kategoria:Konstrukcje programistyczne