2009-04-29 7 views
6

Por lo tanto, actualmente estoy trabajando en un nuevo lenguaje de programación. Inspirado por las ideas de la programación concurrente y Haskell, uno de los principales objetivos del lenguaje es la gestión de los efectos secundarios. Más o menos, se requerirá que cada módulo especifique los efectos secundarios que permite. Entonces, si estuviera haciendo un juego, el módulo de gráficos no tendría la capacidad de hacer IO. El módulo de entrada no podría dibujar en la pantalla. El módulo de IA debería ser totalmente puro. Los scripts y complementos para el juego tendrían acceso a un subconjunto muy restringido de IO para leer los archivos de configuración. Etcétera.¿Cómo debo manejar los efectos secundarios en un nuevo diseño de lenguaje?

Sin embargo, lo que constituye un efecto secundario no es claro. Estoy buscando ideas o sugerencias sobre el tema que pueda considerar en mi idioma. Aquí están mis pensamientos actuales.

Algunos efectos secundarios son evidentes. Ya sea que imprima en la consola del usuario o ejecute sus misiles, cualquier acción que lea o escriba en un archivo propiedad del usuario o que interactúe con hardware externo es un efecto secundario.

Otros son más sutiles y estos son los que realmente me interesan. Estos serían cosas como obtener un número aleatorio, obtener la hora del sistema, dormir un hilo, implementar memoria transaccional de software o incluso algo muy fundamental como como asignación de memoria.

A diferencia de otros lenguajes creados para controlar los efectos secundarios (mirándote Haskell), quiero diseñar mi lenguaje para que sea práctico y pragmático. Las restricciones de los efectos secundarios deben cumplir dos propósitos:

  • Para ayudar en la separación de preocupaciones. (Ningún módulo puede hacer todo).
  • Para guardar en la arena cada módulo de la aplicación. (Cualquier módulo se puede usar como un complemento)

Teniendo esto en cuenta, ¿cómo debo manejar los efectos "pseudo" -side, como números aleatorios y dormir, como menciono arriba? ¿Qué más podría haberme perdido? ¿De qué manera podría administrar el uso de memoria y el tiempo como recursos?

+0

+1 Wow. De hecho, solo iba a hacer una pregunta similar. Estoy diseñando un lenguaje híbrido FP/OOP. – Zifre

Respuesta

0

Dale un vistazo serio al Clojure, y su uso de software transactional memory, agents, and atoms para mantener los efectos secundarios bajo control.

+0

Debo admitir que recorrí el sitio Clojure el día que lo anunciaron por primera vez en Reddit. Creo que el lenguaje es realmente genial. Quería entrar en su desarrollo, pero hay algo acerca de los idiomas lispy que es totalmente desagradable para mí. ¡Me aseguraré de ver qué progresos han hecho desde entonces para obtener ideas! –

+0

Soy un poco curioso de lo que estás lleno no es práctico y práctico sobre Haskell. Es * diferente *, claro, bt hay un buen software real escrito en él. También puedes mirar a Erlang, que ciertamente está viendo un uso práctico. –

+0

O, en inglés, "lo que sientes no es pragmático y práctico". –

1

Un efecto secundario está teniendo cualquier efecto en cualquier cosa en el mundo que no sea devolver un valor, es decir, mutar algo que podría ser visible de alguna manera fuera de la función.

Una función pura no depende ni afecta ningún estado mutable fuera del alcance de esa invocación de la función, lo que significa que la salida de la función solo depende de las constantes y sus entradas. Esto implica que si llama a una función dos veces con los mismos argumentos, se garantiza que obtendrá el mismo resultado ambas veces, independientemente de cómo se escriba la función.

Si tiene una función que modifica una variable que se ha pasado, esa modificación es un efecto secundario porque es salida visible de la función que no sea el valor de retorno. Una función nula que no es no-operativa debe tener efectos secundarios, porque no tiene otra forma de afectar el mundo.

La función podría tener una variable privada solo visible para esa función que lee y modifica, y llamarla aún tendría el efecto secundario de cambiar la forma en que se comporta la función en el futuro. Ser puro significa tener exactamente un canal para la salida de cualquier tipo: el valor de retorno.

Es posible generar números aleatorios puramente, pero debe pasar la semilla al azar manualmente.La mayoría de las funciones aleatorias conservan un valor de inicialización privado que se actualiza cada vez que se llama para que obtenga un azar diferente cada vez. He aquí una Haskell el fragmento con el System.Random:

randomColor    :: StdGen -> (Color, Int, StdGen) 
randomColor gen1   = (color, intensity, gen2) 
where (color, gen2)  = random gen1 
     (intensity, gen3) = randomR (1, 100) gen2 

Las funciones aleatorias cada devuelven el valor aleatorio y un nuevo generador con una nueva semilla (en base a la anterior). Para obtener un nuevo valor cada vez, se debe pasar la cadena de nuevos generadores (gen1, gen2, gen3). Los generadores implícitos solo usan una variable interna para almacenar los valores gen1 .. en el fondo.

Hacer esto manualmente es un problema, y ​​en Haskell puede usar una mónada de estado para que sea mucho más fácil. Deseará implementar algo menos puro o utilizar un recurso como mónadas, flechas o valores de singularidad para abstraerlo.

Obtener el tiempo del sistema es impuro porque el tiempo podría ser diferente cada vez que pregunte.

Dormir es más borroso porque el sueño no afecta el resultado de la función, y siempre se puede retrasar la ejecución con un bucle ocupado, y eso no afectaría a la pureza. La cuestión es que dormir se hace por el bien de otra cosa, que ES un efecto secundario.

La asignación de memoria en los lenguajes puros tiene que suceder implícitamente, porque asignar y liberar explícitamente la memoria son efectos secundarios si puede hacer cualquier tipo de comparaciones con el puntero. De lo contrario, la creación de dos objetos nuevos con los mismos parámetros produciría valores diferentes porque tendrían identidades diferentes (por ejemplo, no ser igual por el operador = = de Java).

Sé que he hablado un poco, pero espero que eso explique los efectos secundarios.

+0

Soy muy consciente de lo que es un efecto secundario. Mi punto era que los efectos secundarios no están totalmente bien definidos. Tenga en cuenta que hablo un poco más vagamente que la definición Haskellesque que proporcionó anteriormente. Mi lenguaje NO será puro. Esto significa que nunca se garantiza que invocar la misma función dos veces sea irreversible. Lo que es importante para mí en mi diseño es simplemente la contención de los efectos secundarios. Hay un mundo de diferencia entre la filosofía de Haskell de que cada valor es inmutable y la simple prevención de que cualquier viejo Joe lance sus misiles. –

4

El problema de cómo describir y controlar los efectos ocupa actualmente algunas de las mejores mentes científicas en lenguajes de programación, incluidas personas como Greg Morrisett de la Universidad de Harvard. Que yo sepa, el trabajo pionero más ambicioso en esta área fue realizado por David Gifford y Pierre Jouvelot en el lenguaje de programación FX iniciado en 1987. El language definition está en línea, pero puede obtener más información sobre las ideas al leer su 1991 POPL paper.

2

Esta es una pregunta realmente interesante, y representa una de las etapas que he vivido y, francamente, ha ido más allá.

Recuerdo seminarios en los que Carl Hewitt, al hablar sobre su formalismo de Actores, discutió esto. Lo definió en términos de un método que daba una respuesta que era únicamente una función de sus argumentos, o que podía dar respuestas diferentes en momentos diferentes.

Digo que me moví más allá porque hace que el lenguaje en sí mismo (o el modelo computacional) sea el tema principal, a diferencia de los problemas que se supone que debe resolver. Se basa en la idea de que el lenguaje debe tener un modelo subyacente formal para que sus propiedades sean fáciles de verificar. Eso está bien, pero sigue siendo un objetivo lejano, porque todavía no hay lenguaje (que yo sepa) en el que la corrección de algo tan simple como el tipo de burbuja sea fácil para probar, y mucho menos sistemas más complejos.

Lo anterior es un buen objetivo, pero la dirección que tomé fue mirar a los sistemas de información en términos de teoría de la información. Específicamente, suponiendo que un sistema comience con un corpus de requisitos (en papel o en la cabeza de alguien), esos requisitos pueden transmitirse a una máquina de escritura de programa (ya sea automática o humana) para generar código fuente para una implementación en funcionamiento. ENTONCES, a medida que se producen cambios en los requisitos, los cambios se procesan a través de cambios delta en el código fuente de implementación.

Entonces la pregunta es: ¿Qué propiedades del código fuente (y el idioma en el que está codificado) facilitan este proceso? Claramente, depende del tipo de problema que se esté resolviendo, qué tipo de información entra y sale (y cuando), por cuánto tiempo debe retenerse la información y qué tipo de procesamiento debe realizarse en ella. De esto uno puede determinar el nivel formal del lenguaje necesario para ese problema.

me di cuenta el proceso de arranque a través de cambios delta de requisitos en el código fuente se hace más fácil ya que el formato del código viene más a asemejan los requisitos, y no hay una manera cuantitativa agradable para medir esta semejanza, no en términos de semejanza superficial, pero en términos de acciones de edición. La tecnología más conocida que mejor expresa esto es el lenguaje específico del dominio (DSL). Entonces me di cuenta de que lo que más busco en un lenguaje de propósito general es la capacidad de crear lenguajes de propósito especial.

Dependiendo de la aplicación, tales lenguajes de propósito especial pueden o no necesitar características formales específicas como notación funcional, control de efectos secundarios, paralelismo, etc. De hecho, hay muchas maneras de hacer un lenguaje de propósito especial, desde analizar, interpretar, compilar, hasta simplemente macros en un idioma existente, hasta simplemente definir clases, variables y métodos en un idioma existente. Tan pronto como declaras una variable o subrutina, creas nuevo vocabulario y, por lo tanto, un nuevo idioma para resolver tu problema. De hecho, en este sentido amplio, no creo que pueda resolver ningún problema de programación sin siendo, en algún nivel, un diseñador de lenguaje.

La mejor de las suertes, y espero que abra nuevas perspectivas para usted.

+0

Gracias por la respuesta. Veré si no puedo encontrar algo sobre los seminarios de Carl Hewitt. No diría que el idioma en sí es el foco central. Realmente no tengo idea de qué tipo de lenguaje voy a escribir todavía. Puedo terminar enfocándome en escribir una máquina virtual en lugar de un idioma y luego presentar un lenguaje de demostración simple para mostrar su mérito. Las DSL y las preocupaciones sobre la productividad del lenguaje no son terriblemente importantes en esta etapa (¡al final, pero aún no del todo!), Pero mis modelos de subprocesamiento y memoria son extremadamente importantes. –

+0

Buena suerte. Aquí hay un comienzo: http://en.wikipedia.org/wiki/Carl_Hewitt Es un tipo inteligente. –

Cuestiones relacionadas