ventajas secuencial programacion paradigmas paradigma imperativa funcional ejemplos desventajas declarativa caracteristicas aplicaciones terminology paradigms

terminology - secuencial - programacion funcional ventajas y desventajas



ProgramaciĆ³n funcional, declarativa e imperativa (14)

Hoy en día, nuevo enfoque: necesitamos las clasificaciones antiguas?

Los aspectos imperativo / declarativo / funcional eran buenos en el pasado para clasificar los idiomas genéricos, pero en la actualidad todos los "grandes lenguajes" (como Java, Python, Javascript, etc.) tienen alguna opción (típicamente frameworks ) para expresar con "otro enfoque" que su principal (imperativo habitual), y para expresar procesos paralelos, funciones declarativas, lambdas, etc.

Entonces, una buena variante de esta pregunta es "¿Qué aspecto es bueno para clasificar los marcos hoy en día?" ... Un aspecto importante es algo que podemos etiquetar "estilo de programación" ...

Foco en la fusión de datos con algoritmo.

Un buen ejemplo para explicar. Como puedes leer sobre jQuery en Wikipedia ,

El conjunto de características principales de jQuery (selecciones de elementos DOM, recorrido y manipulación), habilitado por su motor selector (...), creó un nuevo "estilo de programación", algoritmos de fusión y estructuras de datos DOM

Entonces, jQuery es el mejor (popular) ejemplo de enfoque en un "nuevo estilo de programación" , que no es solo la orientación a objetos, es " Fusionar algoritmos y estructuras de datos ". jQuery es algo reactivo como hojas de cálculo, pero no "orientado a celdas", es " orientado a nodos DOM " ... Comparando los estilos principales en este contexto:

  1. Sin fusión : en todos los "grandes lenguajes", en cualquier expresión funcional / declarativa / imperativa, lo habitual es "sin fusión" de datos y algoritmo, excepto por alguna orientación a objetos, que es una fusión en el punto de vista de la estructura álgebra estricta .

  2. Algunas fusiones : todas las estrategias clásicas de fusión, en la actualidad tienen algún marco que lo usa como paradigma ... dataflow , programación dirigida por eventos (o lenguajes específicos de dominio antiguos como awk y XSLT ) ... Al igual que la programación con hojas de cálculo modernas, también son Ejemplos de estilo de programación reactiva .

  3. Big fusion : es "el estilo jQuery" ... jQuery es un lenguaje específico del dominio que se centra en " algoritmos de fusión y DOM-data-structures ".
    PS: "otros lenguajes de consulta", como XQuery, SQL (PL con opción de expresión como imperativo) son también ejemplos-algorith-fusión de datos, pero son islas , sin fusión con otros módulos del sistema ... Spring , cuando se utiliza find()-variants y cláusulas de especificación , es otro buen ejemplo de fusión.

¿Qué significan los términos funcional, declarativo y programación imperativa?


Al momento de escribir esto, las respuestas más votadas en esta página son imprecisas y confusas en la definición declarativa frente a la imperativa, incluida la respuesta que cita a Wikipedia. Algunas respuestas están combinando los términos de diferentes maneras.

Consulte también mi explicación de por qué la programación de hojas de cálculo es declarativa, independientemente de que las fórmulas muten las celdas.

Además, varias respuestas afirman que la programación funcional debe ser un subconjunto de declarativo. De ese punto depende si diferenciamos "función" de "procedimiento". Vamos a manejar imperativo vs declarativo primero.

Definición de expresión declarativa.

El único atributo que posiblemente puede diferenciar una expresión declarativa de una expresión imperativa es la transparencia referencial (RT) de sus subexpresiones. Todos los demás atributos se comparten entre ambos tipos de expresiones o se derivan de la RT.

Un lenguaje declarativo del 100% (es decir, uno en el que cada expresión posible es RT) no (entre otros requisitos de RT) permite la mutación de valores almacenados, por ejemplo, HTML y la mayoría de Haskell.

Definición de expresión de RT

RT se refiere a menudo como que no tiene "efectos secundarios". El término efectos no tiene una definición precisa, por lo que algunas personas no están de acuerdo en que "sin efectos secundarios" es lo mismo que RT. RT tiene una definición precisa .

Dado que cada subexpresión es conceptualmente una llamada de función, RT requiere que la implementación de una función (es decir, la (s) expresión (s) dentro de la función llamada) no pueda acceder al estado mutable que es externo a la función (acceder al estado local mutable es permitido). En pocas palabras, la función (implementación) debe ser pura .

Definición de función pura

A menudo se dice que una función pura no tiene "efectos secundarios". El término efectos no tiene una definición precisa, por lo que algunas personas no están de acuerdo.

Las funciones puras tienen los siguientes atributos.

  • La única salida observable es el valor de retorno.
  • La única dependencia de salida son los argumentos.
  • los argumentos están completamente determinados antes de que se genere cualquier salida.

Recuerde que RT se aplica a expresiones (que incluye llamadas a funciones) y pureza se aplica a funciones (implementaciones de).

Un ejemplo oscuro de funciones impuras que crean expresiones RT es la concurrencia, pero esto se debe a que la pureza se rompe en la capa de abstracción de interrupción. Realmente no necesitas saber esto. Para hacer expresiones de RT, llamas funciones puras.

Atributos derivados de RT

Cualquier otro atributo citado para la programación declarativa, por ejemplo, la cita de 1999 utilizada por Wikipedia, deriva de RT o se comparte con la programación imperativa. Demostrando así que mi definición precisa es correcta.

Tenga en cuenta que la inmutabilidad de los valores externos es un subconjunto de los requisitos para RT.

  • Los lenguajes declarativos no tienen estructuras de control de bucle, por ejemplo, for y while , debido a la inmutabilidad , la condición del bucle nunca cambiaría.

  • Los lenguajes declarativos no expresan control-flujo aparte del orden de función anidado (también conocido como dependencias lógicas), porque debido a la inmutabilidad , otras elecciones de orden de evaluación no cambian el resultado (ver más abajo).

  • Los lenguajes declarativos expresan "pasos" lógicos (es decir, el orden de llamada a la función RT anidada), pero si cada llamada de función es una semántica de nivel superior (es decir, "qué hacer") no es un requisito de la programación declarativa. La distinción de imperativo es que, debido a la inmutabilidad (es decir, más generalmente a la RT), estos "pasos" no pueden depender del estado mutable, sino del orden relacional de la lógica expresada (es decir, el orden de anidación de las llamadas de función, también conocidas como subexpresiones). ).

    Por ejemplo, el párrafo HTML <p> no se puede mostrar hasta que se hayan evaluado las sub-expresiones (es decir, las etiquetas) en el párrafo. No hay un estado mutable, solo una dependencia de orden debido a la relación lógica de jerarquía de etiquetas (anidación de subexpresiones, que son llamadas de función anidadas análogamente ).

  • Por lo tanto, existe el atributo derivado de la inmutabilidad (más generalmente RT), que las expresiones declarativas, expresan solo las relaciones lógicas de las partes constituyentes (es decir, de los argumentos de la función de la subexpresión) y no las relaciones de estado mutables .

Orden de evaluacion

La elección del orden de evaluación de las subexpresiones solo puede dar un resultado variable cuando cualquiera de las llamadas de función no es RT (es decir, la función no es pura), por ejemplo, se accede a algún estado mutable externo a una función dentro de la función.

Por ejemplo, dadas algunas expresiones anidadas, por ejemplo, f( g(a, b), h(c, d) ) , la evaluación ágil y perezosa de los argumentos de la función dará los mismos resultados si las funciones f , g y h son puras .

Mientras que, si las funciones f , g y h no son puras, entonces la elección del orden de evaluación puede dar un resultado diferente.

Tenga en cuenta que las expresiones anidadas son funciones anidadas conceptualmente, ya que los operadores de expresión son simplemente llamadas a funciones que se enmascaran como prefijo unario, postfijo unario o notación de infijo binario.

Tangencialmente, si todos los identificadores, por ejemplo, a , b , c , d , son inmutables en todas partes, no se puede acceder al estado externo del programa (es decir, E / S), y no hay ruptura de la capa de abstracción, entonces las funciones son siempre puras.

Por cierto, Haskell tiene una sintaxis diferente, f (gab) (hcd) .

Detalles de orden de evaluación

Una función es una transición de estado (no un valor almacenado mutable) desde la entrada a la salida. Para composiciones de RT de llamadas a funciones puras , el orden de ejecución de estas transiciones de estado es independiente. La transición de estado de cada llamada de función es independiente de las demás, debido a la falta de efectos secundarios y al principio de que una función de RT puede ser reemplazada por su valor almacenado en caché . Para corregir una idea errónea popular , la composición monádica pura siempre es declarativa y RT , a pesar del hecho de que la mónada IO de Haskell es posiblemente impura y, por lo tanto, imperativo es el estado del World externo al programa (pero en el sentido de la advertencia a continuación, el lado -los efectos son aislados).

La evaluación impaciente significa que los argumentos de las funciones se evalúan antes de que se llame a la función, y la evaluación perezosa significa que los argumentos no se evalúan hasta (y si) se accede a ellos dentro de la función.

Definición : los parámetros de función se declaran en el sitio de definición de función y los argumentos de función se suministran en el sitio de llamada de función. Conoce la diferencia entre parámetro y argumento .

Conceptualmente, todas las expresiones son (una composición de) llamadas a funciones, por ejemplo, las constantes son funciones sin entradas, los operadores unarios son funciones con una entrada, los operadores de infijo binarios son funciones con dos entradas, los constructores son funciones e incluso las declaraciones de control (por ejemplo, if , for , while ) se pueden modelar con funciones. El orden en que se evalúan estas funciones de argumento (no confundir con el orden de llamada de función anidada) no se declara mediante la sintaxis, por ejemplo, f( g() ) podría evaluar ansiosamente g luego f sobre el resultado de g o podría evaluar f y solo evaluar perezosamente g cuando se necesita su resultado dentro de f .

Advertencia: ningún lenguaje completo de Turing (es decir, que permite una recursión ilimitada) es perfectamente declarativo, por ejemplo, la evaluación perezosa introduce la memoria y el indeterminismo del tiempo. Pero estos efectos secundarios debidos a la elección del orden de evaluación se limitan al consumo de memoria, el tiempo de ejecución, la latencia, la no terminación y la histéresis externa, por lo tanto la sincronización externa.

Programacion funcional

Debido a que la programación declarativa no puede tener bucles, entonces la única forma de iterar es la recursión funcional. Es en este sentido que la programación funcional está relacionada con la programación declarativa.

Pero la programación funcional no se limita a la programación declarativa . La composición funcional puede contrastarse con los subtipos , especialmente con respecto al Problema de Expresión , donde la extensión se puede lograr mediante la adición de subtipos o la descomposición funcional . La extensión puede ser una mezcla de ambas metodologías.

La programación funcional generalmente hace que la función sea un objeto de primera clase, lo que significa que el tipo de función puede aparecer en la gramática en cualquier lugar que cualquier otro tipo pueda. El resultado final es que las funciones pueden ingresar y operar en funciones, lo que proporciona una separación de intereses al enfatizar la composición de la función, es decir, separar las dependencias entre las subcomputaciones de un cálculo determinista.

Por ejemplo, en lugar de escribir una función separada (y emplear la recursión en lugar de los bucles si la función también debe ser declarativa) para cada una de un número infinito de posibles acciones especializadas que podrían aplicarse a cada elemento de una colección, la programación funcional emplea una iteración reutilizable funciones, por ejemplo, map , fold , filter . Estas funciones de iteración introducen una función de acción especializada de primera clase. Estas funciones de iteración repiten la recopilación y llaman a la función de acción especializada de entrada para cada elemento. Estas funciones de acción son más concisas porque ya no necesitan contener las instrucciones de bucle para iterar la colección.

Sin embargo, tenga en cuenta que si una función no es pura, entonces realmente es un procedimiento. Quizás podamos argumentar que la programación funcional que usa funciones impuras, es realmente una programación de procedimiento. Por lo tanto, si estamos de acuerdo en que las expresiones declarativas son RT, entonces podemos decir que la programación de procedimientos no es una programación declarativa y, por lo tanto, podemos argumentar que la programación funcional siempre es RT y debe ser un subconjunto de la programación declarativa.

Paralelismo

Esta composición funcional con funciones de primera clase puede expresar la profundidad en el paralelismo al separar la función independiente.

Principio de Brent: el cálculo con trabajo w y profundidad d se puede implementar en una PRAM de procesador p en el tiempo O (máx (w / p, d)).

Tanto la concurrencia como el paralelismo también requieren programación declarativa , es decir, inmutabilidad y RT.

Entonces, ¿de dónde surgió esta peligrosa suposición de que Paralelismo == Concurrencia? Es una consecuencia natural de los lenguajes con efectos secundarios: cuando su lenguaje tiene efectos secundarios en todas partes, entonces cada vez que intenta hacer más de una cosa a la vez, esencialmente no tiene determinismo causado por el intercalado de los efectos de cada operación. . Entonces, en los lenguajes de efectos secundarios, la única forma de obtener el paralelismo es la concurrencia; Por lo tanto, no es sorprendente que a menudo veamos las dos cosas combinadas.

Orden de evaluación de FP

Tenga en cuenta que el orden de evaluación también afecta los efectos secundarios de terminación y rendimiento de la composición funcional.

Eager (CBV) y perezoso (CBN) son duelos categóricos [ 10 ], porque tienen un orden de evaluación inverso, es decir, si las funciones externas o internas respectivamente se evalúan primero. Imagine un árbol al revés, y luego las ansiosas evaluaciones desde la rama del árbol de funciones inclina la jerarquía de ramas al tronco de funciones de nivel superior; mientras que, perezoso evalúa desde el tronco hasta las puntas de las ramas. Eager no tiene productos conjuntivos ("y", a / k / a "productos" categóricos) y perezoso no tiene coproductos disyuntivos ("o", a / k / a "sumas" categóricas) [ 10 ].

Actuación

  • Ansioso

    Al igual que con la no terminación, eager es demasiado ansioso con la composición funcional conjuntiva, es decir, la estructura de control de la composición hace un trabajo innecesario que no se hace con la pereza. Por example , ansioso e impaciente e innecesariamente mapea la lista completa a valores booleanos, cuando se compone con un pliegue que termina en el primer elemento verdadero.

    Este trabajo innecesario es la causa de la afirmación "hasta" de un factor log n adicional en la complejidad de tiempo secuencial de ansioso contra perezoso, ambos con funciones puras. Una solución es usar funtores (p. Ej., Listas) con constructores perezosos (es decir, ávidos con productos perezosos opcionales), ya que, con entusiasmo, la falta de entusiasmo se origina en la función interna. Esto se debe a que los productos son tipos constructivos, es decir, tipos inductivos con un álgebra inicial en un punto fijo inicial [ 10 ]

  • Perezoso

    Al igual que con la no terminación, perezoso es demasiado perezoso con una composición funcional disyuntiva, es decir, la finalidad coinductiva puede ocurrir más tarde de lo necesario, lo que resulta tanto en un trabajo innecesario como en un no determinismo del retraso que no es el caso con ansioso [ 10 ] [ 10 ] . Ejemplos de finalidad son las excepciones de estado, tiempo, no terminación y tiempo de ejecución. Estos son efectos secundarios imperativos, pero incluso en un lenguaje declarativo puro (por ejemplo, Haskell), hay un estado en la mónada imperativa de OI (nota: ¡no todas las mónadas son imperativas!) Implícita en la asignación de espacio, y el tiempo es un estado relativo al imperativo mundo real. El uso perezoso incluso con coproductos ávidos opcionales filtra "holgazanería" en coproductos internos, porque con perezoso la pereza se origina en la función externa (consulte el ejemplo en la sección Sin terminación, donde == es una función de operador binario externo). Esto se debe a que los coproductos están limitados por la finalidad, es decir, los tipos coinductores con un álgebra final en un objeto final [ 10 ].

    Lazy provoca indeterminismo en el diseño y la depuración de funciones para la latencia y el espacio, cuya depuración está probablemente más allá de las capacidades de la mayoría de los programadores, debido a la disonancia entre la jerarquía de funciones declarada y el orden de evaluación en tiempo de ejecución. Las funciones puras perezosas evaluadas con entusiasmo pueden potencialmente introducir una no terminación no vista previamente en el tiempo de ejecución. A la inversa, las funciones puras ansiosas evaluadas con holgazanería, potencialmente podrían introducir indeterminismo de latencia y espacio nunca antes vistos en el tiempo de ejecución.

No terminación

En el momento de la compilación, debido al problema de detención y la recursión mutua en un lenguaje completo de Turing, generalmente no se puede garantizar que las funciones terminen.

  • Ansioso

    Con ansioso pero no perezoso, para la conjunción de Head "y" Tail , si Head o Tail no termina, entonces respectivamente List( Head(), Tail() ).tail == Tail() o List( Head(), Tail() ).head == Head() no es verdadero porque el lado izquierdo no, y el lado derecho, termina.

    Considerando que, con perezosos ambos lados terminan. Por lo tanto, ansioso es demasiado ansioso con los productos conjuntivos, y no termina (incluidas las excepciones de tiempo de ejecución) en los casos en que no es necesario.

  • Perezoso

    Con flojo pero no ansioso, para la disyunción de 1 "o" 2 , si f no termina, entonces List( f ? 1 : 2, 3 ).tail == (f ? List( 1, 3 ) : List( 2, 3 )).tail no es verdadera porque el lado izquierdo termina y el lado derecho no.

    Considerando que, con ansioso ninguno de los lados termina, por lo que la prueba de igualdad nunca se alcanza. Por lo tanto, perezoso es demasiado perezoso con coproductos disyuntivos, y en esos casos no finaliza (incluidas las excepciones en tiempo de ejecución) después de hacer más trabajo que el que hubiera ansioso.

[ 10 ] Continuaciones declarativas y dualidad categórica, Filinski, secciones 2.5.4 Una comparación de CBV y CBN, y 3.6.1 CBV y CBN en el SCL.

[ 10 ] Continuaciones declarativas y dualidad categórica, Filinski, secciones 2.2.1 Productos y coproductos, 2.2.2 Objetos terminales e iniciales, 2.5.2 CBV con productos perezosos y 2.5.3 CBN con coproductos ansiosos.


Desde que escribí mi respuesta anterior, formulé una nueva definición de la propiedad declarativa que se cita a continuación. También he definido la programación imperativa como la propiedad dual.

Esta definición es superior a la que proporcioné en mi respuesta anterior, porque es concisa y es más general. Pero puede ser más difícil de asimilar, porque las implicaciones de los teoremas de incompletitud aplicables a la programación y la vida en general son difíciles para que los humanos encierren su mente.

La explicación citada de la definición analiza el papel que desempeña la programación funcional pura en la programación declarativa.

Todos los tipos de programación exóticos encajan en la siguiente taxonomía de declarativo versus imperativo, ya que la siguiente definición afirma que son duales.

Declarativo vs Imperativo

La propiedad declarativa es rara, obtusa y difícil de captar en una definición técnicamente precisa que sigue siendo general y no ambigua, porque es una noción ingenua de que podemos declarar el significado (también conocido como semántica) del programa sin incurrir en efectos secundarios no deseados. Existe una tensión inherente entre la expresión del significado y la evitación de los efectos no deseados, y esta tensión en realidad se deriva de los teoremas incompletos de la programación y nuestro universo.

Es una simplificación excesiva, técnicamente imprecisa y, a menudo, ambigua definir declarativo como " qué hacer " e imperativo como " cómo hacer " . Un caso ambiguo es el " qué " es el " cómo " en un programa que genera un programa: un compilador.

Evidentemente, la recursión ilimitada que completa un lenguaje Turing también es análoga en la semántica, no solo en la estructura sintáctica de la evaluación (también conocida como semántica operacional). Este es lógicamente un ejemplo análogo al teorema de Gödel: " cualquier sistema completo de axiomas también es inconsistente ". ¡Reflexiona sobre la rareza contradictoria de esa cita! También es un ejemplo que demuestra cómo la expresión de la semántica no tiene un límite probable, por lo tanto no podemos probar 2 que un programa (y análogamente su semántica) detuvo también conocido como el teorema de Detención.

Los teoremas incompletos se derivan de la naturaleza fundamental de nuestro universo, que, como se afirma en la Segunda Ley de la Termodinámica, es que " la entropía (también conocida como el número de posibilidades independientes) tiende al máximo para siempre ". La codificación y el diseño de un programa nunca se terminan, ¡está vivo! Porque intenta satisfacer una necesidad del mundo real, y la semántica del mundo real siempre está cambiando y se está inclinando hacia más posibilidades. Los seres humanos nunca dejan de descubrir cosas nuevas (incluidos los errores en los programas ;-).

Para capturar de manera precisa y técnica esta noción deseada antes mencionada dentro de este universo extraño que no tiene borde (piénsalo, no hay un "exterior" de nuestro universo), se requiere una definición concisa pero engañosamente no simple que suene incorrecta hasta que se explique profundamente.

Definición:

La propiedad declarativa es donde solo puede existir un posible conjunto de declaraciones que puedan expresar cada semántica modular específica.

La propiedad imperativa 3 es la dual, donde la semántica es inconsistente en la composición y / o puede expresarse con variaciones de conjuntos de declaraciones.

Esta definición de declarativo es distintivamente local en el ámbito semántico, lo que significa que requiere que una semántica modular mantenga su significado coherente independientemente de dónde y cómo se ejemplifique y emplee en el ámbito global . Por lo tanto, cada semántica modular declarativa debe ser intrínsecamente ortogonal a todas las demás posibles, y no un algoritmo o modelo global imposible (debido a teorías incompletas) para presenciar la consistencia, que también es el punto de " Más no siempre es mejor " de Ciencias de la Computación en la Universidad Carnegie Mellon, uno de los diseñadores de Standard ML.

Ejemplos de estos incluyen semántica declarativa modulares categoría funtores teoría, por ejemplo, laApplicative , mecanografía nominal, espacios de nombres, los campos de nombre y WRT a nivel operativo de la semántica a continuación, la programación funcional pura.

Por lo tanto, los lenguajes declarativos bien diseñados pueden expresar un significado más claramente , aunque con cierta pérdida de generalidad en lo que puede expresarse, pero una ganancia en lo que puede expresarse con consistencia intrínseca.

Un ejemplo de la definición antes mencionada es el conjunto de fórmulas en las celdas de un programa de hoja de cálculo, que no se espera que den el mismo significado cuando se mueven a diferentes celdas de columnas y filas, es decir, se cambian los identificadores de celda. Los identificadores de celda son parte y no son superfluos del significado pretendido. Por lo tanto, cada resultado de la hoja de cálculo es único para los identificadores de celda en un conjunto de fórmulas. La semántica modular consistente en este caso es el uso de identificadores de celda como la entrada y salida de funciones puras para fórmulas de celdas (ver más abajo).

Hyper Text Markup Language, también conocido como HTML, el lenguaje para páginas web estáticas, es un ejemplo de un lenguaje declarativo altamente (pero no perfectamente 3 ) que (al menos antes de HTML 5) no tenía capacidad para expresar un comportamiento dinámico. HTML es quizás el lenguaje más fácil de aprender. Para el comportamiento dinámico, un lenguaje de script imperativo como JavaScript generalmente se combinaba con HTML. HTML sin JavaScript se ajusta a la definición declarativa porque cada tipo nominal (es decir, las etiquetas) mantiene su significado consistente bajo la composición dentro de las reglas de la sintaxis.

Una definición competitiva para declarativo es las propiedades commutative e idempotent de las declaraciones semánticas, es decir, las declaraciones se pueden reordenar y duplicar sin cambiar el significado. Por ejemplo, las declaraciones que asignan valores a los campos nombrados se pueden reordenar y duplicar sin cambiar el significado del programa, si esos nombres son de orden modular a cualquier orden implícita. Los nombres a veces implican un orden, por ejemplo, los identificadores de celda incluyen su posición de columna y fila; mover un total en la hoja de cálculo cambia su significado. De lo contrario, estas propiedades requieren implícitamente globalConsistencia de la semántica. En general, es imposible diseñar la semántica de las declaraciones, por lo que se mantienen consistentes si se ordenan o duplican al azar, porque el orden y la duplicación son intrínsecos a la semántica. Por ejemplo, las declaraciones "Foo existe" (o construcción) y "Foo no existe" (y destrucción). Si se considera que la inconsistencia aleatoria es una de las semánticas intencionadas, entonces se acepta esta definición como lo suficientemente general para la propiedad declarativa. En esencia, esta definición es vacua como una definición generalizada porque intenta hacer coherencia ortogonal a la semántica, es decir, desafiar el hecho de que el universo de la semántica es dinámicamente ilimitado y no puede ser capturado en un paradigma de coherencia global .

Requerir las propiedades conmutativas e idempotentes para el (orden de evaluación estructural de) la semántica operacional de nivel inferior convierte la semántica operacional a una semántica modular localizada declarativa , por ejemplo, programación funcional pura (incluyendo recursión en lugar de bucles imperativos). Entonces, el orden operacional de los detalles de la implementación no afecta (es decir, se extiende globalmente ) a la consistencia de la semántica de nivel superior. Por ejemplo, el orden de evaluación de (y teóricamente también la duplicación de) las fórmulas de la hoja de cálculo no importa porque las salidas no se copian en las entradas hasta después de que se hayan calculado todas las salidas, es decir, análogas a las funciones puras.

C, Java, C ++, C #, PHP y JavaScript no son particularmente declarativos. La sintaxis de Copute y la sintaxis de Python están acopladas de forma más declarativa a los resultados deseados , es decir, una semántica sintáctica coherente que elimina lo extraño para que uno pueda comprender el código fácilmente después de haberlo olvidado. Copute y Haskell imponen el determinismo de la semántica operacional y alientan a " no repetirse " (DRY), porque solo permiten el paradigma funcional puro.

2 Incluso cuando podemos probar la semántica de un programa, por ejemplo, con el idioma Coq, esto se limita a la semántica que se expresa en la escritura , y la escritura nunca puede capturar toda la semántica de un programa, ni siquiera para los idiomas que están si Turing no está completo, p. ej., con HTML + CSS es posible expresar combinaciones inconsistentes que, por lo tanto, tienen una semántica indefinida.

3 Muchas explicaciones afirman incorrectamente que solo la programación imperativa tiene sentencias ordenadas sintácticamente. Aclaré esta confusión entre programación imperativa y funcional . Por ejemplo, el orden de las declaraciones HTML no reduce la coherencia de su significado.

Edit: publiqué el siguiente comentario en el blog de Robert Harper:

en programación funcional ... el rango de variación de una variable es un tipo

Dependiendo de cómo se distinga la programación funcional de la imperativa, su ''asignable'' en un programa imperativo también puede tener un tipo que establece un límite en su variabilidad.

La única definición no confusa que aprecio actualmente para la programación funcional es a) funciones como objetos y tipos de primera clase, b) preferencia por recursión sobre loops, y / o c) funciones puras, es decir, aquellas funciones que no afectan la semántica deseada del programa cuando está memorizado (por lo tanto, la programación funcional perfectamente pura no existe en una semántica denotacional de propósito general debido a los impactos de la semántica operacional, por ejemplo, la asignación de memoria ).

La propiedad idempotente de una función pura significa que la función call en sus variables puede ser sustituida por su valor, que no suele ser el caso de los argumentos de un procedimiento imperativo. Las funciones puras parecen ser declarativas de las transiciones de estado no estructuradas entre los tipos de entrada y resultado.

Pero la composición de las funciones puras no mantiene tal consistencia, porque es posible modelar un proceso imperativo de efectos secundarios (estado global) en un lenguaje de programación funcional puro, por ejemplo, la IOMonad de Haskell y, además, es totalmente imposible evitar hacerlo en Cualquier lenguaje de programación funcional puro puro de Turing.

Como wrote en 2012, que parece similar al consenso de los comentarios en su blog reciente , esa programación declarativa es un intento de captar la idea de que la semántica prevista nunca es opaca. Los ejemplos de semántica opaca son la dependencia del orden, la dependencia del borrado de la semántica de nivel superior en la capa semántica operacional (por ejemplo, los conversos no son conversiones y los genéricos reificados limitan la semántica de nivel superior ), y la dependencia de valores variables que no se pueden verificar correcto) por el lenguaje de programación.

Por lo tanto, he concluido que solo los idiomas completos que no son de Turing pueden ser declarativos.

Por lo tanto, un atributo inequívoco y distinto de un lenguaje declarativo podría ser que su producción puede demostrarse que obedece a un conjunto enumerable de reglas generativas. Por ejemplo, para cualquier programa HTML específico (ignorando las diferencias en las formas en que se desvían los intérpretes) que no está en un guión (es decir, no está completo Turing), su variabilidad de salida puede ser enumerable. O más sucintamente, un programa HTML es una función pura de su variabilidad. Ditto un programa de hoja de cálculo es una función pura de sus variables de entrada.

Así que me parece que los lenguajes declarativos son la antítesis de la recursión ilimitada , es decir, según el segundo teorema de incompletitud de Gödel, los teoremas auto-referenciales no pueden ser probados.

Lesie Lamport wrote un cuento de hadas sobre cómo Euclid podría haber trabajado con los teoremas de incompletitud de Gödel aplicados a las pruebas matemáticas en el contexto del lenguaje de programación a la congruencia entre los tipos y la lógica (correspondencia de Curry-Howard, etc.)


En una palabra:

Un lenguaje imperativo especifica una serie de instrucciones que la computadora ejecuta en secuencia (haga esto, luego haga eso).

Un lenguaje declarativo declara un conjunto de reglas acerca de qué resultados deben resultar de qué entradas (por ejemplo, si tiene A, entonces el resultado es B). Un motor aplicará estas reglas a las entradas y dará una salida.

Un lenguaje funcional declara un conjunto de funciones matemáticas / lógicas que definen cómo se traduce la entrada a la salida. p.ej. f (y) = y * y. Es un tipo de lenguaje declarativo.


Imperativo: cómo lograr nuestro objetivo.

Take the next customer from a list. If the customer lives in Spain, show their details. If there are more customers in the list, go to the beginning

Declarativo: lo que queremos lograr.

Show customer details of every customer living in Spain


Realmente no hay ninguna definición objetiva, no ambigua, para estos. Así es como los definiría:

Imperativo : la atención se centra en los pasos que debe tomar la computadora en lugar de lo que hará la computadora (por ejemplo, C, C ++, Java).

Declarativo : la atención se centra en lo que debe hacer la computadora en lugar de cómo debe hacerlo (por ejemplo, SQL).

Funcional : un subconjunto de lenguajes declarativos que tiene un gran énfasis en la recursión


Los imperativos y declarativos describen dos estilos de programación opuestos. imperativo es el enfoque tradicional de la "receta paso a paso", mientras que declarativo es más "esto es lo que quiero, ahora averigua cómo hacerlo".

estos dos enfoques se producen en toda la programación, incluso con el mismo lenguaje y el mismo programa. en general, el enfoque declarativo se considera preferible, ya que libera al programador de tener que especificar tantos detalles, al mismo tiempo que tiene menos posibilidades de errores (si describe el resultado que desea, y algún proceso automático bien probado puede ir hacia atrás desde ese punto a otro). defina los pasos, entonces puede esperar que las cosas sean más confiables que tener que especificar cada paso a mano).

por otro lado, un enfoque imperativo le da más control de nivel bajo: es el "enfoque de microgestor" para la programación. y eso puede permitir al programador explotar el conocimiento sobre el problema para dar una respuesta más eficiente. así que no es inusual que algunas partes de un programa se escriban en un estilo más declarativo, sino que las partes de velocidad crítica sean más imperativas.

Como puede imaginar, el lenguaje que usa para escribir un programa afecta la capacidad declarativa que puede ser: un lenguaje que tiene "inteligencia" incorporada para determinar qué hacer, dada una descripción del resultado, permitirá una declaración mucho más declarativa. enfoque que el programador necesita primero agregar ese tipo de inteligencia con código imperativo antes de poder construir una capa más declarativa en la parte superior. así, por ejemplo, un lenguaje como prólogo se considera muy declarativo porque tiene, incorporado, un proceso que busca respuestas.

Hasta ahora, te darás cuenta de que no he mencionado la programación funcional . eso es porque es un término cuyo significado no está inmediatamente relacionado con los otros dos. en su forma más simple, la programación funcional significa que usas funciones. en particular, que use un lenguaje que admita funciones como "valores de primera clase"; eso significa que no solo puede escribir funciones, sino que también puede escribir funciones que escriben funciones (que escriben funciones que ...), y pasar funciones a funciones En resumen, las funciones son tan flexibles y comunes como las cadenas y los números.

Puede parecer extraño, entonces, que funcional, imperativo y declarativo a menudo se mencionan juntos. La razón de esto es una consecuencia de llevar la idea de programación funcional "al extremo". una función, en su sentido más puro, es algo de matemática: una especie de "caja negra" que toma algo de entrada y siempre da la misma salida. y ese tipo de comportamiento no requiere almacenar variables cambiantes. por lo tanto, si diseña un lenguaje de programación cuyo objetivo es implementar una idea muy pura y matemáticamente influenciada de la programación funcional, terminará rechazando, en gran medida, la idea de los valores que pueden cambiar (en un cierto sentido técnico limitado).

y si lo hace, si limita la forma en que pueden cambiar las variables, casi por accidente termina forzando al programador a escribir programas que son más declarativos, porque una gran parte de la programación imperativa describe cómo cambian las variables, y ya no puede ¡Haz eso! por lo que resulta que la programación funcional, particularmente la programación en un lenguaje funcional, tiende a dar un código más declarativo.

para resumir, entonces:

  • imperativo y declarativo son dos estilos opuestos de programación (los mismos nombres se usan para lenguajes de programación que fomentan esos estilos)

  • La programación funcional es un estilo de programación donde las funciones se vuelven muy importantes y, como consecuencia, los valores cambiantes se vuelven menos importantes. la limitada capacidad de especificar cambios en los valores obliga a un estilo más declarativo.

por lo que la "programación funcional" se describe a menudo como "declarativa".


Programación imperativa significa cualquier estilo de programación donde su programa esté estructurado a partir de instrucciones que describan cómo sucederán las operaciones realizadas por una computadora .

Programación declarativa significa cualquier estilo de programación donde su programa sea una descripción del problema o de la solución, pero no establece explícitamente cómo se realizará el trabajo .

Programación funcional es programación mediante la evaluación de funciones y funciones de funciones ... Como programación funcional (estrictamente definida) significa programación mediante la definición de funciones matemáticas sin efectos secundarios, por lo que es una forma de programación declarativa, pero no es el único tipo de programación declarativa. .

La programación lógica (por ejemplo, en Prolog) es otra forma de programación declarativa. Implica la computación al decidir si una declaración lógica es verdadera (o si puede satisfacerse). El programa suele ser una serie de hechos y reglas, es decir, una descripción en lugar de una serie de instrucciones.

La reescritura de términos (por ejemplo, CASL) es otra forma de programación declarativa. Implica la transformación simbólica de términos algebraicos. Es completamente distinto de la programación lógica y la programación funcional.


imperativo - las expresiones describen la secuencia de acciones a realizar (asociativa)

Declarativo : las expresiones son declaraciones que contribuyen al comportamiento del programa (asociativo, conmutativo, idempotente, monotónico)

funcional - las expresiones tienen valor como único efecto; semántica apoya el razonamiento ecuacional


Algunas buenas respuestas aquí con respecto a los "tipos" señalados.

Presento algunos conceptos adicionales, más "exóticos", a menudo asociados con la multitud de programación funcional:

  • Lenguaje específico del dominio o Programación DSL : creando un nuevo lenguaje para tratar el problema en cuestión.
  • Meta-Programación : cuando tu programa escribe otros programas.
  • Programación evolutiva : donde se construye un sistema que se mejora continuamente o genera generaciones de subprogramas sucesivamente mejores.

Programación declarativa es programación mediante la expresión de una lógica atemporal entre la entrada y la salida, por ejemplo, en pseudocódigo, el siguiente ejemplo sería declarativo:

def factorial(n): if n < 2: return 1 else: return factorial(n-1) output = factorial(argvec[0])

Simplemente definimos una relación llamada ''factorial'' aquí, y definimos la relación entre la salida y la entrada como la relación. Como debería ser evidente aquí, cualquier lenguaje estructurado permite una programación declarativa en cierta medida. Una idea central de la programación declarativa es información inmutable, si asigna a una variable, solo lo hace una vez, y nunca más. Otras definiciones más estrictas implican que puede no haber efectos secundarios, estos lenguajes a veces se llaman ''puramente declarativos''.

El mismo resultado en un estilo imperativo sería:

a = 1 b = argvec[0] while(b < 2): a * b-- output = a

En este ejemplo, no expresamos una relación lógica estática sin tiempo entre la entrada y la salida, cambiamos las direcciones de memoria manualmente hasta que una de ellas obtuvo el resultado deseado. Debe ser evidente que todos los idiomas permiten la semántica declarativa en cierta medida, pero no todos lo imperativos, algunos lenguajes declarativos ''puros'' permiten efectos secundarios y mutaciones por completo.

A menudo se dice que los lenguajes declarativos especifican ''qué se debe hacer'', en lugar de ''cómo hacerlo'', creo que es un nombre inapropiado, los programas declarativos todavía especifican cómo se debe obtener de la entrada a la salida, pero de otra manera, la relación que especifique debe ser computable de manera efectiva (término importante, búsquelo si no la conoce). Otro enfoque es la programación no determinista , que realmente solo especifica qué condiciones cumple un resultado, antes de que su implementación solo agote todas las rutas de prueba y error hasta que tenga éxito.

Los lenguajes puramente declarativos incluyen Haskell y Pure Prolog. Una escala móvil de uno y otro sería: Pure Prolog, Haskell, OCaml, Scheme / Lisp, Python, Javascript, C--, Perl, PHP, C ++, Pascall, C, Fortran, Assembly


Programación imperativa: decirle a la "máquina" cómo hacer algo y, como resultado, sucederá lo que usted quiere que suceda.

Programación declarativa: decirle a la "máquina" lo que le gustaría que sucediera y dejar que la computadora descubra cómo hacerlo.

Ejemplo de imperativo

function makeWidget(options) { const element = document.createElement(''div''); element.style.backgroundColor = options.bgColor; element.style.width = options.width; element.style.height = options.height; element.textContent = options.txt; return element; }

Ejemplo de declarativo

function makeWidget(type, txt) { return new Element(type, txt); }

Nota: La diferencia no es de brevedad, complejidad o abstracción. Como se ha dicho, la diferencia es cómo vs qué .


Creo que tu taxonomía es incorrecta. Hay dos tipos opuestos imperativos y declarativos. Funcional es solo un subtipo de declarativo. Por cierto, wikipedia declara el mismo hecho.


En pocas palabras, cuanto más enfatiza un estilo de programación Qué (hacer) abstrae los detalles de Cómo (hacerlo), más se considera declarativo ese estilo. Lo contrario es cierto para imperativo. La programación funcional está asociada al estilo declarativo.