Estoy interesado en aprender mejor la programación funcional. Para hacerlo, parece obvio que debería obligarme a usar el lenguaje de programación funcional más puro posible. Por lo tanto, estoy pidiendo, más o menos, un ordenamiento de lenguajes de programación funcionales de acuerdo con su pureza.
Me parece que sería más práctico aprender Lisp o Clojure (o Scheme, o Scala, etc.), pero por lo que he escuchado recientemente, Haskell sería muy difícil de superar al enseñar principios de programación funcional a alguien. Todavía no estoy seguro de esto, así que te pregunto: ¿ cuál es el lenguaje de programación funcional más puro? Un pedido sería genial si varios compiten por el magnífico título del lenguaje de programación funcional más puro.
Respuestas:
No hay escala para evaluar el grado de pureza de los lenguajes funcionales. Si el lenguaje permite efectos secundarios es impuro, de lo contrario es puro. Según esta definición, Haskell, Mercury, Clean, etc. son lenguajes funcionales puros; mientras que Scala, Clojure, F #, OCaml, etc.son impuras.
EDITAR: Tal vez debería haber redactado esto como "si el lenguaje no permite efectos secundarios sin que el sistema de tipos lo sepa , es puro. De lo contrario, es impuro".
fuente
IO
mónada). Es solo que el código que causa los efectos secundarios está claramente marcado como tal. No creo que sea útil hablar de lenguajes puros / impuros (¡Haskell te permite programar de manera imperativa! /impuro.IO
mónada es pura. Es la biblioteca de tiempo de ejecución que no es, no su código, ya que sumain
función es básicamente un gran transformador de estado. (Algo así comomain :: World -> World
detrás de escena)program = "some C code"
, y luego el entorno de ejecución trata con el código C. :-)Dado que el objetivo es aprender, y no escribir programas per se, no puede ser más puro que el cálculo Lambda .
El cálculo Lambda existía antes de que se inventaran las computadoras. Se necesitaron varios lógicos expertos trabajando en ello para descubrir cómo hacer la resta (por un tiempo se teorizó que solo era posible sumar y multiplicar).
Aprender cómo los booleanos y los números
if
pueden inventarse a partir de aparentemente nada no pondrá más gasolina en su tanque, pero lo hará mucho más grande.fuente
-1
.Los lenguajes impuros no difieren en principio de los lenguajes imperativos más familiares, especialmente ahora que se han copiado muchos trucos funcionales. Lo que es diferente es el estilo: cómo se resuelven los problemas.
Ya sea que cuente a Haskell como puro o que considere a la mónada IO como impureza, el estilo de Haskell es una forma extrema de este estilo y vale la pena aprenderlo.
La mónada Haskell IO se deriva de la teoría matemática de (por supuesto) mónadas. Sin embargo, para los programadores imperativos, creo que una forma inversa de llegar a las mónadas tiene más sentido.
Fase uno: un lenguaje funcional puro puede devolver fácilmente un valor de cadena grande como resultado. Esta gran cadena puede ser el código fuente de un programa imperativo, derivado de una manera puramente funcional de algunos parámetros que especifican requisitos. A continuación, puede crear un compilador de "nivel superior" que ejecute su generador de código, luego alimenta automáticamente ese código generado en el compilador de lenguaje imperativo.
Fase dos: en lugar de generar código fuente textual, genera un árbol de sintaxis abstracta fuertemente tipado. Su compilador de lenguaje imperativo se absorbe en su compilador de "nivel superior" y acepta el AST directamente como código fuente. Esto está mucho más cerca de lo que hace Haskell.
Sin embargo, esto todavía es incómodo. Por ejemplo, tiene dos tipos distintos de funciones: las evaluadas durante la fase de generación de código y las ejecutadas cuando se ejecuta el programa generado. Es un poco como la distinción entre funciones y plantillas en C ++.
Entonces, para la fase 3, haga que los dos sean iguales: la misma función con la misma sintaxis puede evaluarse parcialmente durante la "generación de código", o evaluarse completamente, o no evaluarse en absoluto. Además, descarte todos los nodos AST de construcción en bucle a favor de la recursividad. De hecho, descarte la idea de los nodos AST como un tipo especial de datos por completo: no tenga nodos AST de "valor literal", solo tenga valores, etc.
Esto es más o menos lo que hace la mónada IO: el operador de enlace es una forma de componer "acciones" para formar programas. No es nada especial, solo una función. Se pueden evaluar muchas expresiones y funciones durante la "generación de código", pero las que dependen de los efectos secundarios de E / S deben tener una evaluación retrasada hasta el tiempo de ejecución, no por ninguna regla especial, sino como consecuencia natural de las dependencias de datos en expresiones
Las mónadas en general son solo generalizaciones: tienen la misma interfaz, pero implementan las operaciones abstractas de manera diferente, por lo que en lugar de evaluar una descripción del código imperativo, evalúan otra cosa. Tener la misma interfaz significa que hay algunas cosas que puede hacer a las mónadas sin importar qué mónada, lo que resulta útil.
Esta descripción sin duda hará explotar las cabezas de los puristas, pero para mí explica algunas de las razones reales por las que Haskell es interesante. Borra el límite entre la programación y la metaprogramación, y utiliza las herramientas de programación funcional para reinventar la programación imperativa sin necesidad de una sintaxis especial.
Una crítica que tengo de las plantillas de C ++ es que son una especie de sublenguaje funcional puro roto en un lenguaje imperativo: para evaluar la misma función básica en tiempo de compilación en lugar de tiempo de ejecución, debe volver a implementarla usando un estilo completamente diferente de codificación En Haskell, aunque la impureza debe etiquetarse como tal en su tipo, la misma función exacta puede evaluarse tanto en un sentido de metaprogramación como en un sentido de no metaprogramación en tiempo de ejecución en el mismo programa: no hay una línea dura entre programación y metaprogramación.
Dicho esto, hay algunas cosas de metaprogramación que Haskell estándar no puede hacer, básicamente porque los tipos (y tal vez algunas otras cosas) no son valores de primera clase. Sin embargo, hay variantes de idioma que intentan abordar esto.
Muchas de las cosas que he dicho sobre Haskell pueden aplicarse en lenguajes funcionales impuros, y en ocasiones incluso en lenguajes imperativos. Haskell es diferente porque no tienes más remedio que adoptar este enfoque, básicamente te obliga a aprender este estilo de trabajo. Puede "escribir C en ML", pero no puede "escribir C en Haskell", al menos no sin saber lo que sucede debajo del capó.
fuente
Personalmente clasifico los idiomas en tres niveles de pureza funcional:
Lenguajes funcionales puros , es decir, aquellos que tratan todo su programa como una función pura y manejan la mutabilidad únicamente a través de la interacción con el tiempo de ejecución. Haskell es probablemente el ejemplo canónico.
Lenguajes funcionales impuros , es decir, aquellos que enfatizan un estilo funcional pero permiten efectos secundarios. Clojure está claramente en esta categoría (permite la mutación de forma controlada como parte de su marco STM), también OCaml o F #
Lenguajes de paradigmas múltiples : estos no son lenguajes funcionales en primer lugar, pero pueden admitir un estilo funcional mediante el uso de funciones de primera clase, etc. Scala es un buen ejemplo aquí, también pondría Common Lisp en esta categoría e incluso podría incluir idiomas como JavaScript .
En su situación, sugeriría aprender primero Haskell, luego Clojure. ¡Esto fue lo que hice y funcionó muy bien para mí! Haskell es hermoso y te enseña los principios funcionales más puros, Clojure es mucho más pragmático y te ayuda a hacer mucho mientras sigues siendo muy funcional de corazón.
Realmente no cuento la tercera categoría como lenguajes funcionales (aunque después de aprender Haskell y Clojure, ¡a menudo me encuentro aprovechando las técnicas funcionales cuando las uso!)
fuente
Si un lenguaje funcional puro es tal, que solo tiene funciones puras (rutinas que no tienen efectos secundarios), entonces es un poco inútil, porque no puede leer la entrada o escribir la salida;)
Debido a que esto es realmente para aprender, creo que el aislamiento no es necesariamente el camino a seguir. La programación funcional es un paradigma. Es importante comprender qué paradigmas son adecuados para qué problemas y, lo que es más importante, cómo se pueden combinar mejor.
Aparte de eso, si buscas "pureza", quizás quieras echarle un vistazo a Pure . Sin embargo, tenga en cuenta que la extrema facilidad de llamar a las rutinas C lo hace funcionalmente impuro (pero también muy poderoso).
fuente
No es una respuesta completamente seria, pero Unlambda tiene que ser un contendiente. No se puede obtener más "puramente funcional" que los combinadores de SKI.
fuente
Erlang, Haskell, Scheme, Scala, Clojure y F #
Probablemente, esta pregunta sea mejor para ayudarlo en su búsqueda también .
fuente
set!
(entre otras cosas) ...