functional programming - Continuaciones en Clojure
functional-programming scheme (7)
Leí en algún lugar donde rico hickey dijo:
"Creo que las continuaciones pueden ser claras en teoría, pero no en la práctica"
No estoy familiarizado con clojure.
1. ¿Tiene clojure continuaciones?
2. Si no, ¿no necesitas continuaciones? He visto muchos buenos ejemplos, especialmente de este tipo . ¿Cuál es la alternativa?
3. En caso afirmativo, ¿hay alguna documentación?
¿Es la continuación una característica necesaria en un idioma?
No. Muchos idiomas no tienen continuaciones.
Si no, ¿no necesitas continuaciones? He visto muchos buenos ejemplos, especialmente de este tipo. ¿Cuál es la alternativa?
Una pila de llamadas
Continuaciones abstractas
Las continuaciones son una noción abstracta que se utiliza para describir la semántica del flujo de control. En este sentido, ambos existen y no existen (recuerde, son abstractos) en cualquier idioma que ofrezca operadores de control (como debe ser el lenguaje completo de Turing), de la misma manera que existen los números (como entidades abstractas) y No existen (como entidades tangibles).
Las continuaciones describen los efectos de control, como la función de llamada / retorno, manejo de excepciones e incluso gotos. Una lengua bien fundada, entre otras cosas, se diseñará con abstracciones que se basan en continuaciones (por ejemplo, excepciones). (Es decir, un lenguaje bien fundado consistirá en operadores de control que fueron diseñados teniendo en cuenta las continuaciones. Por supuesto, es perfectamente razonable que un lenguaje exponga las continuaciones como la única abstracción de control, lo que permite a los usuarios construir su propia versión). abstracciones en la parte superior.
Continuaciones de primera clase
Si la noción de una continuación se reified como un objeto de primera clase en un lenguaje, entonces tenemos una herramienta sobre la cual se pueden construir todo tipo de efectos de control. Por ejemplo, si un idioma tiene continuaciones de primera clase, pero no excepciones, podemos construir excepciones sobre las continuaciones.
Problemas con continuaciones de primera clase
Si bien las continuaciones de primera clase son una herramienta poderosa y útil en muchos casos, también hay algunos inconvenientes para exponerlas en un idioma:
- Diferentes abstracciones construidas sobre continuaciones pueden resultar en un comportamiento inesperado / no intuitivo cuando se componen. Por ejemplo, un bloque
finally
podría omitirse si uso una continuación para abortar un cálculo. - Si la continuación actual se puede solicitar en cualquier momento, entonces el tiempo de ejecución del idioma debe estar estructurado de modo que sea posible producir una representación de la estructura de datos de la continuación actual en cualquier momento. Esto supone cierto grado de carga en el tiempo de ejecución de una característica que, para bien o para mal, a menudo se considera "exótica". Si el idioma está alojado (como Clojure está alojado en la JVM), esa representación debe poder encajar dentro del marco proporcionado por la plataforma de alojamiento. También puede haber otras características que un idioma quisiera mantener (por ejemplo, interoperabilidad C) que restringen el espacio de la solución. Problemas como estos aumentan el potencial de una "falta de coincidencia de impedancia" y pueden complicar gravemente el desarrollo de una solución eficaz.
Agregar continuaciones de primera clase a un idioma
A través de la metaprogramación, es posible agregar soporte para continuaciones de primera clase a un idioma. En general, este enfoque implica transformar el código en un estilo de paso de continuación (CPS), en el que la continuación actual se transmite como un argumento explícito para cada función.
Por ejemplo, la biblioteca https://github.com/swannodette/delimc David Nolen implementa continuaciones delimitadas de partes de un programa Clojure a través de una serie de transformaciones macro. En una vena similar, he creado pulley.cps , que es un compilador de macros que transforma el código en CPS, junto con una biblioteca en tiempo de ejecución para admitir más funciones principales de Clojure (como el manejo de excepciones), así como la interoperabilidad con el código nativo de Clojure .
Un problema con este enfoque es cómo manejar el límite entre el código nativo (Clojure) y el código transformado (CPS). Específicamente, dado que no puede capturar la continuación del código nativo, debe rechazar (o de alguna manera restringir) la interoperabilidad con el idioma base o colocar una carga en el usuario para asegurar que el contexto permita que cualquier continuación que desee capturar realmente ser capturado
pulley.cps tiende hacia lo último, aunque se han hecho algunos intentos para permitir que el usuario maneje esto. Por ejemplo, es posible no permitir que el código CPS llame al código nativo. Además, se proporciona un mecanismo para suministrar versiones CPS de funciones nativas existentes.
En un lenguaje con un sistema de tipo suficientemente fuerte (como Haskell), es posible usar el sistema de tipo para encapsular cálculos que podrían usar operaciones de control (es decir, continuaciones) de código funcional puro.
Resumen
Ahora tenemos la información necesaria para responder directamente a sus tres preguntas:
- Clojure no admite continuaciones de primera clase debido a consideraciones prácticas.
- Todos los idiomas se basan en continuaciones en el sentido teórico, pero pocos lenguajes exponen las continuaciones como objetos de primera clase. Sin embargo, es posible agregar continuaciones a cualquier idioma mediante, por ejemplo, la transformación en CPS.
- Echa un vistazo a la documentación para https://github.com/swannodette/delimc y / o pulley.cps .
Bueno ... Clojure''s ->
implementa lo que buscas ... Pero con una macro en su lugar
Clojure (o más bien clojure.contrib.monads
) tiene una mónada de continuación; Aquí hay un artículo que describe su uso y motivación .
Cuando se habla de continuaciones, tendrá que distinguir dos tipos diferentes de ellas:
Continuaciones de primera clase: soporte de continuación que está profundamente integrado en el lenguaje (Scheme o Ruby). Clojure no admite continuaciones de primera clase.
Estilo de aprobación (CPS): CPS es solo un estilo de codificación y cualquier lenguaje que admita funciones anónimas permitirá este estilo (que también se aplica a Clojure).
Ejemplos:
-- Standard function
double :: Int -> Int
double x = 2 * x
-- CPS-function – We pass the continuation explicitly
doubleCPS :: Int -> (Int -> res) -> res
doubleCPS x cont = cont (2 * x)
; Call
print (double 2)
; Call CPS: Continue execution with specified anonymous function
double 2 (/res -> print res)
Lea la continuation en Wikipedia.
No creo que las continuaciones sean necesarias para un buen lenguaje, pero especialmente las continuaciones de primera clase y CPS en lenguajes funcionales como Haskell pueden ser bastante útiles ( ejemplo de retroceso inteligente ).
He escrito un puerto Clojure de cl-cont que agrega continuaciones a Common Lisp.
Un uso común de las continuaciones es en la implementación de estructuras de control para: regresar de una función, interrumpir un ciclo, manejar excepciones, etc. La mayoría de los lenguajes (como Java, C ++, etc.) proporcionan estas características como parte del lenguaje central. Algunos idiomas no (por ejemplo: Esquema). En su lugar, estos lenguajes exponen las continuaciones como objetos de primera clase y permiten al programador definir nuevas estructuras de control. Por lo tanto, Scheme debe considerarse como un conjunto de herramientas de lenguaje de programación, no como un lenguaje completo en sí mismo.
En Clojure, casi nunca necesitamos utilizar las continuaciones directamente, porque casi todas las estructuras de control son proporcionadas por la combinación de lenguaje / VM. Sin embargo, las continuaciones de primera clase pueden ser una herramienta poderosa en manos del programador competente. Especialmente en Scheme, las continuaciones son mejores que las equivalentes equivalentes en otros idiomas (como el par setjmp / longjmp en C). This artículo tiene más detalles sobre esto.
Por cierto, será interesante saber cómo Rich Hickey justifica su opinión sobre las continuaciones. ¿Algún enlace para eso?