2009-07-13 16 views
7

Esto está relacionado con What is call/cc?, pero no quería secuestrar esta pregunta para mis propios fines, y algunos de sus argumentos como la analogía de setjmp/longjmp me evaden.Detalles de call/cc

Creo que tengo una idea suficiente sobre lo que es una continuación, la considero una instantánea de la pila de llamadas actual. No quiero entrar en la discusión por qué esto podría ser interesante o qué puedes hacer con las continuaciones. Mi pregunta es más específica, ¿por qué tengo que proporcionar un argumento de función para llamar/cc? ¿Por qué no llama/cc solo devuelve la continuación actual, por lo que puedo hacer lo que me plazca con ella (almacenarla, llamarla, lo que sea)? En un enlace de esta otra pregunta (http://community.schemewiki.org/?call-with-current-continuation-for-C-programmers), se trata de "Esencialmente, es solo una forma limpia de obtener la continuación para usted y evitar los saltos posteriores al punto guardado", pero no estoy recibiendo eso. Parece innecesariamente complicado.

+0

Al revisar este hilo, no tengo muy claro qué era lo que buscaba, y por qué encontró la publicación LtU iluminada. ¿Tal vez podrías editar esta pregunta para explicar mejor estas cosas? –

+0

Creo que la pregunta aún refleja exactamente el punto con el que estaba luchando, y probablemente fue el término "prueba" del póster de LtU que me dio la razón, ya que me hizo pensar en las consecuencias de simplemente devolver la continuación, cuando invocarlo. La cita de la URL de schemewiki.org en la pregunta básicamente capturó todo esto, pero como dije entonces, no lo entendí. Fue justo en mi cara, pero no "vi". La comprensión no depende linealmente de la información, y algunas veces necesita un giro. – ThomasH

+0

OK, lo tengo! El punto sobre el camino tortuoso hacia la comprensión es justo, pero es un poco frustrante intentar responder una pregunta, y no ser capaz de descubrir por qué la persona que la cuestionó lo rechazó. –

Respuesta

2

Contra netiquette SO SOO estoy respondiendo mi propia pregunta, pero más como el editor que el proveedor de la respuesta.

Después de un tiempo comencé una pregunta similar en LtU. Después de todo, estos son los tipos que reflexionan sobre el diseño del lenguaje todo el día, ¿verdad? Y uno de los answers finalmente se puso en marcha conmigo. Ahora las cosas mencionadas aquí, p. por Eli o en la pregunta original, tiene mucho más sentido para mí. Es todo acerca de lo que se incluye en la continuación, y donde la continuidad aplicado establece en

Uno de los posters en LTU escribió:.

"se puede ver exactamente cómo llamar/cc le permite" mantener fuera del camino. "Con em o get/cc necesita hacer algún tipo de prueba para determinar si tiene un salto hacia atrás o simplemente la llamada inicial. Básicamente, call/cc mantiene el uso de la continuación fuera de la continuación , mientras que con get/cc o em, la continuación contiene su uso y por lo tanto (generalmente) debe agregar una prueba al comienzo de la continuación (es decir, inmediatamente después de get/cc/em) para separar el "uso de las partes de continuación" de las partes "resto de la continuación".

Eso lo llevó a casa para mí.

¡Gracias a todos!

+0

Creo que el proveedor de continuación de Derek (centro excluido) se puede implementar usando get/cc. Si encuentro tiempo, lo verificaré. –

2

Eso sería menos versátil. Si quieres que el comportamiento, sólo se puede hacer:

(call/cc (lambda (x) x)) 

Usted puede echar un vistazo a los ejemplos de usos de las continuaciones de Llamada con Patrones de continuación corrientes '8ª Conferencia en el patrón de Idiomas "Darrell Ferguson y Dwight Deugo.'. de Programas. Septiembre de 2001. " (http://library.readscheme.org/page6.html) e intente reescribirlos usando una llamada/retorno de cc, definida como arriba.

+0

Gracias por mostrar cómo podría degradarme a este caso de esquina. Pero quería una explicación, no una solución. – ThomasH

9

Si usa una construcción como Jay muestra, entonces puede tomar la continuación, pero de alguna manera, el valor que se agarra ya está dañado porque ya está dentro de esa continuación. Por el contrario, call/cc se puede utilizar para tomar la continuación que es todavía pendiente fuera de la expresión actual. Por ejemplo, uno de los usos más simples de continuaciones es implementar una especie de abort:

(call/cc (lambda (abort) 
      (+ 1 2 (abort 9)))) 

No se puede hacer eso con la operación que usted describe. Si lo intenta:

(define (get-cc) (call/cc values)) 
(let ([abort (get-cc)]) (+ 1 2 (abort 9))) 

continuación, se produce un error acerca de la aplicación 9 como un procedimiento. Esto sucede porque abort salta de nuevo a la let con el nuevo valor de 9 - lo que significa que usted ahora está haciendo una segunda ronda de la misma expresión Además, salvo que ahora está obligado a abort9 ...

Dos notas relacionadas adicionales:

  1. Para una buena introducción práctica a las continuaciones, vea PLAI.
  2. call/cces un poco complejo en el sentido de que adopta una función: una construcción conceptualmente más fácil de usar es let/cc que puede encontrar en algunas implementaciones como PLT Scheme. El ejemplo anterior se convierte en (let/cc abort (+ 1 2 (abort 9))).
+0

Entonces, lo que dices en términos de mi pregunta, es (a) si la continuación se devuelve inmediatamente, se "estropea" porque estoy dentro de la continuación. Pero no puedo estar dentro de una continuación a menos que lo llame. Si las continuaciones son valores de primera clase, no pueden estropearse pasándoselos, ¿verdad? Luego, dices (b) call/cc obtendría una continuación "pendiente". ¿Cómo puede estar pendiente un valor?También dices (c) que la continuación está "fuera" de la expresión actual. No lo entiendo del todo. ¿Cuánto captura la continuación? Todo hasta, pero sin incluir, la llamada a call/cc ?! – ThomasH

+0

Sí, ya estás dentro de la continuación. Lo que sucede con las continuaciones es que representan el cómputo "futuro" después de que se realiza la expresión call/cc actual, por lo que una vez que finalizas (call/cc (lambda (k) k)) procedes inmediatamente a la continuación que acabas de capturar –

+0

Tenga en cuenta, por cierto, que la vista de "una continuación representa la pila actual" es útil para implementarla, pero no para entenderla. Una mejor forma de verlo si quieres entenderlo es verlo como el contexto. Por ejemplo, la continuación que se une a k en (lista 1 2 (call/cc (lambda (k) k)) 3 4) es el contexto que está esperando una respuesta, y luego procederá a evaluar 3 y 4, luego aplique la lista en los 5 valores. En otras palabras, lo ve como: (lista 1 2 [...] 3 4). Esto puede ser difícil de hacer, porque en la mayoría de los casos este contexto es global. Ver esas referencias que señalé. –

2

Sugiero comenzar preguntándose: ¿qué significa ser una continuación de primera clase?

La continuación de una expresión consiste esencialmente en dos datos: primero, el cierre (es decir, el entorno) de esa expresión; y segundo, una representación de lo que debería hacerse con el resultado de la expresión. Un lenguaje con continuaciones de primera clase, entonces, tiene estructuras de datos que encapsulan estas partes y que trata estas estructuras de datos como lo haría con cualquier otra.

call/cc es una forma particularmente elegante de realizar esta idea: la continuación actual se empaqueta como un procedimiento que encapsula lo que se debe hacer con la expresión como lo que hace el procedimiento cuando se aplica a la expresión; representar la continuación de esta manera simplemente significa que el cierre de este procedimiento contiene el entorno en el sitio donde se invocó.

Puede imaginarse realizando la idea de continuaciones de primera clase de otras maneras. No serían call/cc, y es difícil para mí imaginar cómo una representación así podría ser más simple.

En una nota de despedida, examinar la ejecución del Let/cc que Eli se ha mencionado, que yo prefiero llamar a bind/cc:

(define-syntax bind/cc 
    (syntax-rules() 
     ((bind/cc var . body) 
      (call/cc (lambda (var) . body))))) 

Y como un ejercicio, ¿cómo poner en práctica la llamada/cc basa en bind/cc?

+0

Gracias por la publicación, pero está, una vez más, demasiado alejado de mi pregunta como para dejarme una respuesta. – ThomasH