scheme racket continuations delimited-continuations

scheme - ¿Qué es exactamente un "aviso de continuación"?



racket continuations (1)

¿Qué es un aviso, conceptualmente?

El esquema en general tiene la idea de continuaciones , pero Racket extiende esto con la idea de continuaciones delimitadas . La idea de una continuación es que capture el cálculo restante que queda por evaluar. No intentaré explicar las continuaciones en general, ya que está fuera del alcance de esta pregunta.

Sin embargo, explicaré qué hace que las continuaciones delimitadas sean especiales. Por lo general, capturar una continuación captura todo el cálculo, hasta el nivel superior. Esto hace que sus usos sean relativamente limitados para implementar estructuras de control complicadas porque la aplicación de una continuación liberará completamente el control de la ejecución del programa.

Con continuaciones delimitadas, puede capturar solo una cierta parte de la continuación. Las partes de la evaluación que realmente se capturan están delimitadas por indicaciones , que actúan como marcadores a lo largo de la continuación actual que especifican qué parte de la continuación se capturará.

Está bien, pero ¿qué significa eso?

El concepto de las continuaciones delimitadas no está realmente claro sin verlo realmente en acción en comparación con las continuaciones no limitadas.

Continuaciones estándar (no delimitadas)

Considere el siguiente código de ejemplo.

(define *k* #f) (sqrt (+ 1 2 3 (call/cc (λ (k) (set! *k* k) 0))))

Este código es muy sencillo: captura una continuación y almacena en el enlace global *k* . La continuación en sí se ve así:

(sqrt (+ 1 2 3 _))

(Donde el _ representa el "agujero" que se debe completar al llamar a la continuación).

Aplicar esta continuación funcionaría exactamente como uno esperaría.

> (*k* 3) ; evaluates (sqrt (+ 1 2 3 3)) 3

Todo esto es muy ordinario. Entonces, ¿cuál es la diferencia introducida por las continuaciones delimitadas?

Continuaciones delimitadas

¿Qué pasa si solo quisiéramos capturar parte de la continuación en *k* . Por ejemplo, ¿y si solo quisiéramos capturar esta continuación?

(+ 1 2 3 _) ; the inner portion of the last continuation

Podemos hacer esto estableciendo un aviso de continuación , que ajustará qué parte de la continuación se captura realmente.

(sqrt (call-with-continuation-prompt (λ () (+ 1 2 3 (call/cc (λ (k) (set! *k* k) 0))))))

Ahora, aplicando *k* da el resultado interno:

> (*k* 3) 9

Una analogía para continuaciones delimitadas.

Las continuaciones pueden ser un concepto un tanto abstracto, por lo que si el ejemplo de código anterior no es perfectamente claro, considere esta analogía.

El modelo de evaluación es una pila: cada llamada de función empuja un nuevo marco a la pila y, al regresar de una función, se extrae ese marco de la pila. Podemos visualizar la pila de llamadas como una pila de cartas.

Normalmente, cuando se captura una continuación, captura el cuadro actual y todos los cuadros debajo de él, como se visualiza a continuación.

El nivel superior, representado en azul, no se captura. Es efectivamente el indicador predeterminado en un sistema delimitado.

Sin embargo, la instalación de un nuevo mensaje crea una especie de divisor transparente entre los marcos, que afecta a qué marcos se capturan como parte de la continuación.

Este divisor delimita el alcance de la continuación.

Apéndice: Etiquetas de aviso y barreras de continuación

Estos son los conceptos básicos de las continuaciones delimitadas, pero hay otras formas de controlar las continuaciones que le dan aún más poder al sistema de continuación (además de protegerlo de códigos maliciosos), y son etiquetas rápidas y barreras de continuación.

La idea de una etiqueta de solicitud es esencialmente una "etiqueta" que marca una solicitud dada. Usando la analogía de la tarjeta anterior, a cada divisor transparente se le puede asignar una etiqueta. Luego, cuando captura una continuación, puede especificar capturar todo el camino de regreso a esa etiqueta específica , incluso si hay otras indicaciones con otras etiquetas en el medio.

Las barreras de continuación , por otro lado, son una medida de seguridad. Al igual que las indicaciones, se pueden visualizar como "divisores" que se sientan entre los elementos de la pila de llamadas, pero en lugar de usarse como marcas para controlar la cantidad de la pila que se captura, sirven como guardias para evitar que las continuaciones salten "a través" del barrera.

Para obtener más detalles sobre esto, considere leer la sección en la referencia de Raqueta sobre barreras de continuación . Aquí hay un extracto:

Específicamente, una continuación puede ser reemplazada por otra solo cuando el reemplazo no introduce ninguna barrera de continuación. Puede eliminar barreras de continuación solo a través de saltos a continuaciones que son una cola de la continuación actual. Por lo tanto, una barrera de continuación evita que los “saltos hacia abajo” se conviertan en una continuación que está protegida por una barrera.

Estoy tratando de descifrar la documentación.

call-with-continuation-prompt

Aplica proc a los arg dados con la continuación actual extendida por un aviso. La solicitud está etiquetada por la etiqueta de prompt-tag , que debe ser un resultado de la etiqueta de prompt-tag default-continuation-prompt-tag predeterminada (la predeterminada) o la make-continuation-prompt-tag . El resultado de proc es el resultado de la call-with-continuation-prompt llamada call-with-continuation-prompt .

Entiendo la parte en la que dice "Aplica proc a los arg dados con la continuación actual" y luego es simplemente un alboroto desde allí.

¿Qué significa incluso que una continuación se "extienda" y cómo un "aviso" hace esto "extendiéndose"?