Continuaciones en Scheme

Slides:



Advertisements
Presentaciones similares
Curso de java básico (scjp)
Advertisements

Interpretando objetos
EXCEPCIÓN DE ERRORES.
Funciones en lenguaje C
Teoría de lenguajes y compiladores
Nombre, Alcance y Asociaciones (Bindings). Agenda Definición Nombre y Bindings Binding Time Importancia del Binding Time Eventos relacionados a la Asociación.
16/04/ Sesión 11 Funciones y procedimientos Ing. Ricardo Inquilla.
1 LENGUAJES LOGICOS IMPLEMENTACION CALCULO DE PREDICADOS PROLOG.
Paradigmas de Programación 2. Paradigma Imperativo
Cobol C Pascal Fortran 5. UNIDADES DE PROGRAMAS SmallTalk Java C++
Paso de parámetros y arreglos. Las aplicaciones (llamadas a procedimiento) Resolución de nombres (gracias al establecimiento de un ambiente) Condicionamiento.
Subrutinas y Control de Abstracción
Extensiones sintácticas Revisaremos formas especiales que son sintácticamente equivalentes a patrones que son expresables en términos de formas básicas.
Agenda Clase 16 Motivación e Historia de la Programación Funcional y la Programación Lógica. Concepto y Características de la Programación Funcional. Ventajas.
Alcance Dinámico La Asociación Actual para un Nombre dado es el encontrado recientemente durante la ejecución, y no a sido destruido aun por el retornado.
FUNCIONES Conceptos básicos. Retorno de una función Clases de funciones. Paso de parámetros. Funciones y arrays.
Herencia. Introducción La idea básica es poder crear clases basadas en clases ya existentes. Cuando heredamos de una clase existente, estamos re-usando.
1 5. UNIDADES DE PROGRAMAS. 2 Uso de mecanismos de control de secuencia de: Invocaciones Retornos Entre: PPSP 1 a) I R SP 1 SP 2 b) I R Unidades subordinadas.
Departamento de Informática Universidad Técnica Federico Santa María Lenguajes Funcionales Francisco Bórquez Departamento de Informática Universidad Técnica.
AYUDANTÍA 2 Lenguaje Imperativo y Java. Punteros Dirección a memoria (puede apuntar a NULL). Permite trabajar con memoria (variables dinámicas de heap).
Las tres primeras fases de un compilador suelen agrupan en un sola fase llamada Análisis del programa a compilar y las tres ultimas en una sola fase llamada.
Administración de Sistemas Gestores de Bases de Datos.
PROGRAMACIÓN ORIENTADA A OBJETOS SEGUNDA UNIDAD: “CLASES, OBJETOS Y MÉTODOS” IRVING YAIR SALAS CHÁVEZ ING. EN SISTEMAS COMPUTACIONALES - ITSLP.
Funciones en lenguaje C 2 Funciones Definición: – Las funciones son los bloques de construcción básicos de C. Dentro de ellas se da toda la actividad.
Manejo de Excepciones Agustín J. González ELO329 ELO329.
Repaso Programacion en C
Polimorfismo y Funciones Virtuales
Colecciones Carlos Fontela, 2008.
INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS
Exception Object Throwable Error Exception Runtime Exception.
Estructuras de Datos Recursividad.
Definición y Conversión de datos
Estructuras de Datos MC Beatriz Beltrán Martínez Primavera 2016
UN DISPARADOR O TRIGGER es un procedimiento que se ejecuta cuando se cumple una condición establecida al realizar una operación. Es una rutina autónoma.
Programación orientada a objetos
INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS
Manejo de Excepciones Agustín J. González ELO329.
Sonia Rueda Herencia y Polimorfismo
Polimorfismo y Métodos Virtuales
Programación Orientada a Objetos I Unidad 4 Relaciones entre clases: herencia.
Herencia en C#.
Manejo de Excepciones Agustín J. González ELO329.
Manejo de Punteros y objetos en memoria dinámica en C++
LÓGICA DE PROGRAMACIÓN
Algoritmo Capitulo Cinco.
Plantillas (Templates)‏
Algunas Características de C++ no presentes en C
Manejo de Excepciones Agustín J. González ELO329.
CONCEPTOS PRELIMINARES (Cont)
Manejo de Excepciones Agustín J. González ELO329.
Manejo de Punteros y objetos en memoria dinámica en C++
ABSTRACCION DE DATOS   Estructura de Datos Básicos: En programación una estructurad de datos, es una forma particular de organizar datos en una computadora.
Fundamentos de la Programación I
Estructuras Dinámicas
TEMAS *Arboles Binarios *listas Abiertas y Cerradas - Inserción - Recorrido - Eliminación *Pilas - Concepto - Inserción - Recorrido -
Estructura general de un programa. Estructura general de un programa. Pseudocódigo Diagrama de flujo Concepto de programas. Concepto de programas. Instrucciones.
Manejo de Punteros y objetos en memoria dinámica en C++
Árboles Binarios Estructuras de Datos.
Recursividad 1 Análisis de algoritmos. Matrushka La Matrushka es una artesanía tradicional rusa. Es una muñeca de madera que contiene otra muñeca más.
Algunas Características de C++ no presentes en C
Manejo de Excepciones Agustín J. González ELO329 ELO329.
Manejo de Excepciones en C++
Programación Modular Programación de Computadoras - Hugo Vega Grupo2: Reina Rodríguez Miriam Salluca.
Manejo de excepciones Escuela de Ingeniería de Sistemas y Computación Universidad del Valle INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS (IPOO)
Manejo de Punteros y objetos en memoria dinámica en C++
Asignación Dinámica de Memoria
Árboles Binarios Estructuras de Datos. Las estructuras dinámicas son las en la ejecución varia el número de elementos y uso de memoria a lo largo del.
Pipelining Peligros de control.
Algunas Características de C++ no presentes en C
Templates (en español: Pantillas, modelos, patrones)‏
Transcripción de la presentación:

Continuaciones en Scheme Luis Mateu

Definición Una continuación es la abstracción de la cadena de llamadas de procedimientos. En Scheme se trata de un objecto funcional con un solo parámetro. Toda invocación de función recibe un argumento implícito que es su continuación. Por ejemplo: f -> g -> h. La continuación de h es una función que ejecuta el retorno a la función g.

En otros lenguajes C: setjmp, longjmp. El destino debe existir, si no, segmentation fault. Java: try-catch, throw. Garantiza que el destino existe. Pero en Scheme las continuaciones son mucho más poderosas

Continuaciones de primera clase En Scheme las continuaciones pueden ser de primera clase: se pueden almacenar en variables, vectores, pasar como argumentos y ser retornados. Esto se hace con: (call-with-current-continuation proc) En donde proc debe tener la forma: (lambda (kont) ...) “kont” es la continuación de 1era. clase.

Uso: Reificación Se usan para lograr escapes dinámicos: (call/cc ; call-with-current-continuation (lambda (exit-fun) ... (lambda (...) (exit-fun val) )))) Se usan para lograr corrutinas

Ejemplo: búsqueda exhaustiva (define (full-search sym tree) (call/cc (lambda (kont) (define (search tree) (cond ((eq? sym tree) (kont #t)) ((pair? tree) (search (car tree)) (search (cdr tree)) ))) ; cuerpo del lambda (search tree) #f )))

Variante: return (define (full-search sym tree) (call/cc (lambda (return) (define (search tree) (cond ((eq? sym tree) (return #t)) ((pair? tree) (search (car tree)) (search (cdr tree)) ))) ; cuerpo del lambda (search tree) #f )))

Variante: paso como parámetro (define (search sym tree kont) (cond ((eq? sym tree) (kont #t)) ((pair? tree) (search sym (car tree) kont) (search sym (cdr tree) kont) ))) (define (full-search sym tree) (call/cc (lambda (kont) (search syn tree kont) #f )))

Múltiples invocaciones (let ( (v 1) (kont '()) ) (set! kont (call/cc (lambda (k) (k k)))) (display v) (newline) (set! v (+ v 1)) (if (<= v 10) (kont kont) )) No se entiende? Sin embargo la semántica es una sola! Abre un sin número de posibilidades para escribir programas ilegibles!

Múltiples invocaciones (let ( (v 1) (kont (call/cc (lambda (k) (k k)))) ) (display v) (newline) (set! v (+ v 1)) (if (<= v 10) (kont kont) )) ; equivale a: ( (lambda (v kont) (1 (call/cc (lambda (k) (k k)))) ) Las implementaciones no necesariamente implementan correctamente call/cc.

Historia Las primeras versiones de Scheme solo tenían escapes en la forma de catch/throw. Idea: como especificar la semántica de Scheme? En particular, la semántica de catch/throw. Solución: traducir los programas a una máquina abstracta. Todas las implementaciones deben entregar el mismo resultado que la máquina abstracta. Lenguaje de la máquina abstracta: lambda cálculo.

Problema: efectos de borde En lambda cálculo no hay efectos de borde. Solución: Mapa de asociación entre variables y valores El mapa se pasa como argumento a todas las funciones La asignación crea un nuevo mapa a partir del mapa actual. Cómo se retorna?

Problema: escapes Lambda cálculo no tiene escapes catch/throw. Solución: estilo de paso de continuaciones (CPS) Los procedimientos nunca retornan Reciben un parámetro adicional: la continuación En vez de retornar, se invoca la continuación

Ejemplo: fib No se entiende nada? (define (fib n) ; estilo normal (if (<= n 2) 1 (+ (fib (- n 1) (fib (- n 2))) )) (define (kfib n k) ; estilo cps (k 1) (kfib (- n 1) (lambda (res1) (kfib (- n 2) (lambda (res2) (k (+ res1 res2) )))))) No se entiende nada?

Ejemplo: búsqueda exhaustiva (2) (define (full-search sym tree k1) (define (search tree k2) (cond ((eq? sym tree) (k1 #t)) ((pair? tree) (search (car tree) (lambda (dummy) (search (cdr tree) k2) ))) (else (k2 'void)) )) ; cuerpo de full-search (search tree (lambda (val) (k1 #f))) ) No se entiende, pero no hay ambigüedad sobre como implementarlo!

Implementación de referencia La implementación de referencia traduce los programas a CPS (continuation passing style). Implementa los efectos laterales de manera funcional por medio de una mapa de asociaciones (look up table). Una implementación real nunca lo hace así, pero debe entregar el mismo resultado. La implementación de referencia define la semántica del lenguaje. En Scheme, esta implementación de referencia se llama semántica denotacional.

Semántica denotacional

Implementación de referencia de call/cc Tan simple como: (define (call/cc proc kont) (proc kont kont) ) La idea era sólo especificar catch/throw, pero esta definición también sirve para dar un significado a continuaciones con: invocaciones hacia arriba múltiples invocaciones!

Corrutinas Procesos con paso explícito del control (non preemptive) (define c (start proc)): crea una corrutina. (resume c): transfiere el control a la corrutina c. (current): entrega el identificador de la corrutina en ejecución Ejemplo: (same-fringe '(a (b c)) '((a b) c)) => true

Implementación (define *eot* '(eot)) ; fin del árbol (define (same-fringe tree-a tree-b) ; Crea una corrutina para cada árbol (let ((t-a (make-walker tree-a)) (t-b (make-walker tree-b))) ; Obtiene cíclicamente una hoja para cada árbol (let loop ((leaf-a (resume t-a 'any)) (leaf-b (resume t-b 'any))) (cond ((eq? leaf-a *eot*) ; no more leaves on tree-a (eq? leaf-b *eot*)) ((eq? leaf-a leaf-b) ; get a new leaf for each ; tree and loop (loop (resume t-a 'any) (resume t-b 'any))) (else ; Encontró dos hojas diferentes #f) ))))

Implementación (cont) (define (make-walker tree) (start (lambda (t-comp) ; t-comp es el identificador del padre (define (walk-tree tree) ; Recorre el árbol (if (atom? tree) (resume t-comp tree) ; else (begin (walk-tree (car tree)) (walk-tree (cdr tree)) ))) ; pass my thread-id (resume t-comp (current-thread)) ; now traverse the tree (walk-tree tree) ; Finally, pass the end-token *eot* )))

Como implementar call/cc Directamente: transformar a CPS No hay pila: todas las llamadas son recursivas por la cola. Las variables están en el heap. Ineficiente. Duplicar las pilas Para respetar la semántica de call/cc se requiere que toda variable asignada con set! quede en el heap. No tan eficiente. La mayoría de las implementaciones lo hace, pero algunas no.

Conclusiones Call/cc otorga una expresividad inigualable a Scheme: escapes + corrutinas < call/cc Pero es difícil implementar eficientemente las invocaciones múltiples de una continuación. Piquer y yo propusimos una semántica de corrutinas para Scheme en donde: escapes + corrutinas = call/cc Es compatible con call/cc, excepto en las invocaciones múltiples.

Bibliografía Draft paper “Continuations: Multiple Invocations Considered Harmful”, Mateu y Piquer. Contiene un survey de artículos acerca de continuaciones.