haskell - orientada - programacion funcional ventajas y desventajas
Rasgos distintivos de los lenguajes funcionales (7)
Se sabe que todos los lenguajes funcionales comparten algunas propiedades básicas, como el uso de funciones como elemento básico para los programas con todas las consecuencias, como el uso de recursividad en lugar de iteración. Sin embargo, también existen algunas diferencias fundamentales. Lisp usa una sola representación para el código Lisp y los datos, mientras que ML no tiene una representación estándar del código ML. Erlang tiene una concurrencia integrada basada en actores. Haskell tiene mónadas. Haskell hace una distinción en el sistema de tipo estático entre funciones puras e impuras; ML no lo hace.
¿Cuáles son las diferencias fundamentales distintivas entre otros lenguajes funcionales (Clojure, F #, Arc, cualquier otro)? Por fundamental me refiero a algo que influye en la forma en que se desarrolla en este lenguaje, y no por ejemplo, si está integrado con algún tiempo de ejecución ampliamente difundido.
¿Propiedades fundamentales?
- Pureza funcional (falta de efectos secundarios)
- Como un empate de lo anterior, falta de estado.
- Patrones de coincidencia en funciones
El primero es hermoso, el segundo es un feo efecto secundario del anterior (juego de palabras).
La compensación en el mundo real por la falta de estado es lo que considero que es el mayor diferenciador entre los lenguajes funcionales.
Esas pocas cosas dan muchos regalos. La mayoría de las veces, los idiomas manejan la memorización.
Cuando dices código como datos, te refieres a un lenguaje donde el código se representa en una estructura de datos. A esto se lo conoce como Homoiconicidad y, por lo general, solo se aplica a los idiomas que son dialectos de lisp o algo parecido. Haskell, Erlang y Scala no son homocónicos, Clojure sí.
Los diferenciadores fundamentales de Clojure son:
Tiene un sistema de memoria transaccional de software, que facilita la programación concurrente de estado compartido
Es un Lisp, a diferencia de Haskell o Erlang, por lo tanto, todos los códigos son datos, lo que le permite realizar cambios de apariencia que le gustan al lenguaje en el tiempo de ejecución a través del sistema de macros.
Se ejecuta en JVM, lo que significa que tiene acceso directo a todas las bibliotecas de Java
Las estructuras de datos de Clojure implementan interfaces Java tales como Collection, List, Map, Runnable y Callable, según corresponda. Las cadenas son solo cadenas de Java, los números son enteros y dobles de Java. Esto significa que las estructuras de datos de Clojure se pueden pasar directamente a las bibliotecas de Java sin ningún tipo de puente o traducción
Hay muchas diferencias, pero solo dos diferencias que categorizaría como fundamentales porque marcan una gran diferencia para tu desarrollo:
- Sistema de tipo polimórfico tipado dinámicamente vs estático con tipos de datos algebraicos e inferencia tipo. Un sistema de tipo estático restringe un poco el código, pero tiene muchas ventajas:
- Los tipos son documentación que es verificada por el compilador.
- El sistema de tipos lo ayuda a elegir qué código escribir a continuación, y cuando no está seguro de qué escribir, el sistema de tipos le ayuda a eliminar de manera fácil y rápida muchas alternativas.
- Un sistema poderoso, moderno y de tipo polimórfico es irrazonablemente bueno para detectar errores pequeños y tontos que consumen tiempo.
- La evaluación diferida como valor predeterminado en todas partes frente a la evaluación diferida restringida a construcciones cuidadosamente controladas.
- Lazy vs Eager tiene enormes implicaciones para su capacidad de predecir y comprender los costos de tiempo y espacio de sus programas.
- En un lenguaje completamente vago, puede desacoplar completamente la producción de datos de las decisiones sobre qué hacer con los datos una vez producidos. Esto es especialmente importante para los problemas de búsqueda, ya que es mucho más fácil modularizar y reutilizar el código.
Me gusta la respuesta de Chris Conway que establece algunos ejes importantes que ayudan a clasificar diferentes lenguajes funcionales.
En términos de características de idiomas específicos, escogeré F # para llamar algunas características que no se encuentran en muchos otros FPL:
- Patrones activos : varios FPL tienen tipos de datos algebraicos y coincidencia de patrones, pero la función F # llamada "patrones activos" le permite definir nuevos patrones que le permiten usar sintaxis de coincidencia de patrones en datos arbitrarios.
- Expresiones de cálculo : F # tiene un hermoso azúcar sintáctico para crear código monádico; aunque el sistema de tipos no puede expresar un polimorfismo de alto grado (sin abstracción sobre los constructores de tipo), no puedes escribir código para una mónada M arbitraria, el código que puedes escribir para una mónada fija es muy bueno y la gente escribe grandes comprensiones en el seq {} o async {} mónadas.
- Citas : el bit habitual de "código como datos para la metaprogramación", aunque F # tiene un sistema expresivo de tipo estático y una rica sintaxis, y no estoy seguro de cuántos no-cepos pueden hacer esto.
En términos de clasificación general, F # es
- ansioso (estricto, call-by-value; pero ''perezoso'' es una palabra clave y una biblioteca y usar seq / IEnumerable para un poco de pereza es una estrategia común)
- impuro (aunque la sintaxis te sesga hacia un estilo más puro por defecto)
- estático (con inferencia de tipo, por lo que F # a menudo ''parece scripting'', solo con seguridad tipo)
Su pregunta está formulada de una manera clara con algunas pragmáticas extra-idiomáticas (por ejemplo, con qué tiempo de integración se integra), pero también pregunta qué "influye en la forma en que se desarrolla", y estas cosas influyen en eso:
- La integración de Visual Studio significa una gran experiencia de edición (por ejemplo, Intellisense)
- La integración de Visual Studio significa una gran experiencia de depuración (por ejemplo, puntos de interrupción / puntos de referencia, locales, ventana inmediata, ...)
- REPL para secuencias de comandos o UI-on-the-fly es hotness (línea de comandos fsi.exe, o "F # Interactive" integrado en VS)
- La integración de .NET significa que para la mayoría de ''X'' ya hay una biblioteca para hacer eso
- herramientas secundarias como FsLex / FsYacc, e integración con MSBuild que hace que el ''sistema de compilación'' sea fácil
(Creo que intentar separar un idioma de su tiempo de ejecución y herramientas es un ejercicio principalmente académico).
Así que hay una descripción de muchas de las características distintivas de un idioma en particular del que soy fanático. Espero que otros publiquen respuestas similares que denotan características distintivas de otros idiomas individuales.
La Programación Funcional es un estilo, no una construcción de lenguaje
La mayoría de los lenguajes funcionales tienen algunos principios comunes:
- Objetos inmutables
- Cierres y funciones anónimas
- Algoritmos genéricos
- Continuaciones
Pero el principio más importante es que generalmente te obligan a escribir en un estilo funcional. Puede programar en un estilo funcional en la mayoría de los idiomas. C # podría considerarse "funcional" si escribe código así, como cualquier otro idioma.
La parte superior de mi cabeza:
- perezoso vs. ansioso (también conocido como no estricto vs. estricto o llamado por necesidad vs. call-by-value ): ¿se evalúan los argumentos de funciones antes de la aplicación de la función, o después, o nunca?
- puro vs. impuro : ¿permite el lenguaje que las funciones tengan efectos secundarios? ¿Tiene referencias mutables?
- estático vs. dinámico : ¿los tipos de verificación de idioma en tiempo de compilación o tiempo de ejecución?
- tipos de datos algebraicos : ¿coincide el patrón de compatibilidad de idiomas con los tipos de variante?
- metaprogramación : ¿el lenguaje proporciona un poderoso sistema de generación de código?
- concurrencia y paralelismo : ¿son los hilos / procesos una abstracción de primera clase? ¿El lenguaje facilita la ejecución de múltiples cálculos al mismo tiempo?
- Tipos "exóticos" : ¿qué tan expresivo es el sistema de tipo estático? GADTs? Tipos dependientes? Tipos lineales? Sistema F?
Solo los primeros dos elementos son realmente únicos para los lenguajes funcionales (es decir, casi todos los lenguajes imperativos son entusiastas e impuros).
Evaluación no estricta versus estricta.
Escritura estática vs dinámica.
Tipificación estructural vs nominal estática. OCaml es el único lenguaje que se me ocurre con la tipificación estructural (tanto en objetos como en variantes polimórficas), lo que cierra la brecha con el tipado dinámico al eliminar la necesidad de definir muchos tipos (por ejemplo, tipos de variantes).
Derivados de Hindley-Milner frente a otros algoritmos de inferencia de tipo estático. SML, OCaml, Haskell y F # utilizan algoritmos de inferencia de tipo basados en Hindley-Milner, mientras que Scala solo tiene inferencia de tipo local (como C # 3) y requiere muchas más anotaciones para compilar. (El código Haskell a menudo está lleno de anotaciones de tipo en el nivel de función, pero la mayoría son innecesarias y se agregan para la documentación y para ayudar al compilador en presencia de errores).
Comparación de patrones versus deconstrucción manual. SML, OCaml, F #, Haskell, Mathematica y Scheme automatizan la deconstrucción de valores.
Tipos de suma cerrada vs solo tipos de suma abierta. SML, OCaml, F # y Haskell permiten definir tipos algebraicos cerrados / sellados para fortalecer el tipado estático al transmitir implícitamente restricciones más específicas. OCaml y F # también permiten tipos de suma abierta, mientras que SML no y Haskell requiere una solución elaborada (descrita por Oleg Kiselyov).
Patrones de tiempo limitado. La coincidencia de patrones es muy rápida en SML y (vainilla) OCaml pero tiene un rendimiento desconocido en F # debido a patrones activos e incluso complejidad asintótica desconocida en Mathematica.
Compilación sobre la marcha del código nativo. F #, Lisp y Scheme permiten que el código se genere, compile y ejecute eficientemente en tiempo de ejecución.
Macros. OCaml, Mathematica, Lisp y Scheme son lenguajes extensibles.
Estandarizado vs propietario. SML, Haskell 2010, Common Lisp y Scheme son lenguajes estandarizados, mientras que OCaml, Erlang, F # y Mathematica son propietarios.