![]()
![]()
![]()
![]()
![]()
Next: La Paire Up: Eléments avancés Previous: Eléments du langage   Contents   Index
Le futur d'un programmeLes continuations sont en Scheme des fonctions qui représentent le futur de l'exécution d'un programme à un certain point de la continuation. Elles sont construites avec la fonction call-with-current-continuation aussi appelée call/cc. Cette fonction a comme argument une fonction à un argument qui recevra la continuation construite par call/cc :
(call/cc (lambda (continuation) ...))La fonction passée à call/cc , ici, une lambda-expression, est invoquée avec comme argument la continuation. Si elle n'utilise pas cette continuation et se déroule jusqu'à la fin, la valeur de call/cc est la valeur de retour de la fonction. On aura par exemple :
Osm> (call/cc (lambda (continuation) (+ 1 2 3))) => 6La continuation est elle-même une fonction à un argument. Si cette fonction est invoquée avec une valeur, cette valeur devient immédiatement la valeur de retour de l'appel à call/cc :
Osm> (call/cc (lambda (continuation) (continuation "toto") ; le reste n'est pas exécuté (+ 1 2 3))) => "toto"Utilisons une continuation dans une fonction qui retourne le premier élément de type caractère d'une liste quelconque, et la valeur fausse si aucun caractère n'est trouvé :
(define (premier-caractère liste) (call/cc (lambda (continuation) (do ((ptr liste (cdr liste))) ((null? ptr) #f) (if (char? (car ptr)) (continuation (car ptr)))))))Notons que l'on aurait pu renommer la variable continuation en return, ou tout autre nom.
Mais où est le futur dans tout ça ?
Eh bien le futur est dans la continuation. En effet, une continuation est un objet de première classe, qui peut donc être manipulé comme tout autre objet. Il est donc possible d'affecter à une variable une continuation, et d'invoquer cette continuation de n'importe où.
Dans ce contexte, la continuation peut être vue comme une sorte de goto.
Réalisons un petit programme qui s'occupe de lire des nombre au clavier et de les afficher. Si autre chose qu'un nombre est lu, une erreur est provoquée :
; Continuation affectée plus bas. ; En cas d'appel, après l'init, va ; au retour du call/cc (A) (define encore #f) ; lit des nombre au clavier (define (lit) (let ([valeur (read)]) (cond [(eof-object? valeur) #f] [(number? valeur) valeur] [else (erreur "mauvais noombre!")])) ; traitement des erreurs (let ([compteur 0] [message ; A: retour du call/cc (call/cc (lambda (cont) (set! erreur cont) #f))]) ; à l'init, message vaut #f (if message (begin (display "ERREUR(") (display compteur) (display "): ") (display message) (newline))) (set! compteur (+ compteur 1))) ; boucle de programme (do ([nombre (lit) (lit)]) ((not nombre)) (display nombre) (newline))Lorsque l'on exécute ce programme, la variable encore reçoit la valeur de la continuation de l'appel à call/cc. Puis on entre dans une boucle.
Cette boucle lit un nombre au clavier, l'affiche et recommence. Lorsque la fin de fichier est rencontrée, la boucle et le programme se terminent.
Lorsque autre chose qu'un nombre est entré, la fonction erreur est invoquée. Elle affiche un message, puis invoque la continuation encore.
Cette invocation ramène l'exécution à la fin du call/cc, c'est à dire avant la boucle : en effet, le futur du call/cc, lors de sa première invocation est bien l'exécution de la boucle. Donc l'invocation de cette continuation ramène toujours avant ce futur.
Ce programme peut servir de structure pour construire un interprète plus complexe. Les continuations peuvent aussi servir à réaliser les fameux threads, pour peu que l'on dispose de timers.
![]()
![]()
![]()
![]()
![]()
Next: La Paire Up: Eléments avancés Previous: Eléments du langage   Contents   Index © 1993 to 2001 Erian Concept