Pregunta

He leído los artículos de Wikipedia para ambos. programación procesal y programación funcional, pero todavía estoy un poco confundido.¿Alguien podría reducirlo al núcleo?

¿Fue útil?

Solución

Un lenguaje funcional (idealmente) le permite escribir una función matemática, es decir.una función que toma norte argumentos y devuelve un valor.Si se ejecuta el programa, esta función se evalúa lógicamente según sea necesario.1

Un lenguaje procedimental, por otro lado, realiza una serie de secuencial pasos.(Existe una forma de transformar la lógica secuencial en lógica funcional llamada estilo de paso de continuación.)

Como consecuencia, un programa puramente funcional siempre produce el mismo valor para un insumo, y el orden de evaluación no está bien definido;lo que significa que los valores inciertos como la entrada del usuario o los valores aleatorios son difíciles de modelar en lenguajes puramente funcionales.


1 Como todo lo demás en esta respuesta, es una generalización.La propiedad de evaluar un cálculo cuando se necesita su resultado en lugar de secuencialmente cuando se solicita se conoce como "pereza", y no todos los lenguajes funcionales son universalmente perezosos, ni la pereza se limita a la programación funcional.Más bien, la descripción dada aquí proporciona un "marco mental" para pensar en diferentes estilos de programación que no son categorías distintas y opuestas, sino ideas fluidas.

Otros consejos

Básicamente los dos estilos son como el Yin y el Yang.Uno es organizado, mientras que el otro es caótico.Hay situaciones en las que la programación funcional es la opción obvia y otras situaciones en las que la programación procedimental es la mejor opción.Es por eso que hay al menos dos lenguajes que recientemente han lanzado una nueva versión que abarca ambos estilos de programación. ( Perl6 y D 2 )

Procesal:

  • La salida de una rutina no siempre tiene una correlación directa con la entrada.
  • Todo se hace en un orden específico.
  • La ejecución de una rutina puede tener efectos secundarios.
  • Tiende a enfatizar la implementación de soluciones de forma lineal.

Perla 6

re 2

int factorial( int n ){

  int result = 1;

  for( ; n > 0 ; n-- ){
    result *= n;
  }

  return result;
}

Funcional:

  • A menudo recursivo.
  • Siempre devuelve la misma salida para una entrada determinada.
  • El orden de evaluación suele ser indefinido.
  • Debe ser apátrida.es decir.Ninguna operación puede tener efectos secundarios.
  • Buen ajuste para ejecución paralela
  • Tiende a enfatizar un enfoque de divide y vencerás.
  • Puede tener la característica de Evaluación diferida.

Haskell

( copiado de Wikipedia );

fac :: Integer -> Integer

fac 0 = 1
fac n | n > 0 = n * fac (n-1)

o en una línea:

fac n = if n > 0 then n * fac (n-1) else 1

Perla 6

re 2

pure int factorial( invariant int n ){
  if( n <= 1 ){
    return 1;
  }else{
    return n * factorial( n-1 );
  }
}

Nota al margen:

Factorial es en realidad un ejemplo común para mostrar lo fácil que es crear nuevos operadores en Perl 6 de la misma manera que crearía una subrutina.Esta característica está tan arraigada en Perl 6 que la mayoría de los operadores en la implementación de Rakudo se definen de esta manera.También le permite agregar sus propios candidatos múltiples a los operadores existentes.

Este ejemplo también muestra la creación de rangos (2..$n) y el metaoperador de reducción de lista ([ OPERATOR ] LIST) combinado con el operador de multiplicación infijo numérico.(*)
También muestra que puedes poner --> UInt en la firma en lugar de returns UInt después de.

(Puede salirse con la suya comenzando el rango con 2 ya que el "operador" multiplicado volverá 1 cuando se llama sin ningún argumento)

Nunca he visto esta definición en ningún otro lugar, pero creo que esto resume bastante bien las diferencias que se dan aquí:

Funcional La programación se centra en expresiones

Procesal La programación se centra en declaraciones

Las expresiones tienen valores.Un programa funcional es una expresión cuyo valor es una secuencia de instrucciones que debe ejecutar la computadora.

Las declaraciones no tienen valores y en cambio modifican el estado de alguna máquina conceptual.

En un lenguaje puramente funcional no habría declaraciones, en el sentido de que no hay forma de manipular el estado (aún podrían tener una construcción sintáctica llamada "declaración", pero a menos que manipule el estado, no lo llamaría declaración en este sentido). ).En un lenguaje puramente procedimental no habría expresiones, todo sería una instrucción que manipula el estado de la máquina.

Haskell sería un ejemplo de lenguaje puramente funcional porque no hay forma de manipular el estado.El código de máquina sería un ejemplo de lenguaje puramente procedimental porque todo en un programa es una declaración que manipula el estado de los registros y la memoria de la máquina.

La parte confusa es que la gran mayoría de los lenguajes de programación contienen ambos Expresiones y afirmaciones, permitiéndole mezclar paradigmas.Los lenguajes se pueden clasificar como más funcionales o más procedimentales en función de cuánto fomentan el uso de declaraciones frente a expresiones.

Por ejemplo, C sería más funcional que COBOL porque una llamada a una función es una expresión, mientras que llamar a un subprograma en COBOL es una declaración (que manipula el estado de las variables compartidas y no devuelve un valor).Python sería más funcional que C porque le permite expresar la lógica condicional como una expresión usando una evaluación de cortocircuito (prueba && ruta1 || ruta2 en lugar de declaraciones if).Scheme sería más funcional que Python porque todo en Scheme es una expresión.

Aún puedes escribir en un estilo funcional en un lenguaje que fomente el paradigma procesal y viceversa.Simplemente es más difícil y/o más incómodo escribir en un paradigma que el lenguaje no fomenta.

En informática, la programación funcional es un paradigma de programación que trata la computación como la evaluación de funciones matemáticas y evita estados y datos mutables.Enfatiza la aplicación de funciones, en contraste con el estilo de programación procedimental que enfatiza los cambios de estado.

Creo que la programación procedimental/funcional/objetiva trata sobre cómo abordar un problema.

El primer estilo planificaría todo en pasos y resuelve el problema implementando un paso (un procedimiento) a la vez.Por otro lado, la programación funcional enfatizaría el enfoque de divide y vencerás, donde el problema se divide en subproblemas, luego cada subproblema se resuelve (creando una función para resolver ese subproblema) y los resultados se combinan para crear la respuesta para todo el problema.Por último, la programación objetiva imitaría el mundo real creando un minimundo dentro de la computadora con muchos objetos, cada uno de los cuales tiene características (algo) únicas e interactúa con otros.De esas interacciones surgiría el resultado.

Cada estilo de programación tiene sus propias ventajas y debilidades.Por lo tanto, hacer algo como "programación pura" (es decir,puramente procedimental (nadie hace esto, por cierto, lo cual es un poco extraño) o puramente funcional o puramente objetivo) es muy difícil, si no imposible, excepto algunos problemas elementales especialmente diseñados para demostrar la ventaja de un estilo de programación (por lo tanto, A los que les gusta la pureza los llamamos "weenie" :D).

Luego, a partir de esos estilos, tenemos lenguajes de programación que están diseñados para optimizarse para cada estilo.Por ejemplo, la Asamblea tiene que ver con los procedimientos.Bien, la mayoría de los lenguajes antiguos son procedimentales, no solo Asm, como C, Pascal (y Fortran, según escuché).Luego, tenemos el famoso Java en la escuela objetiva (en realidad, Java y C# también están en una clase llamada "orientada al dinero", pero eso es tema de otra discusión).También objetivo es Smalltalk.En la escuela funcional, tendríamos la familia Lisp y la familia ML "casi funcionales" (algunos los consideraban impuros) y muchos Haskell, Erlang, etc. "puramente funcionales".Por cierto, existen muchos lenguajes generales como Perl, Python, Ruby.

Para ampliar el comentario de Konrad:

Como consecuencia, un programa puramente funcional siempre produce el mismo valor para una entrada y el orden de evaluación no está bien definido;

Debido a esto, el código funcional generalmente es más fácil de paralelizar.Dado que (generalmente) las funciones no tienen efectos secundarios y (generalmente) simplemente actúan según sus argumentos, muchos problemas de concurrencia desaparecen.

La programación funcional también se utiliza cuando es necesario ser capaz de prueba tu código es correcto.Esto es mucho más difícil de hacer con la programación procedimental (no es fácil con la funcional, pero aún más fácil).

Descargo de responsabilidad:No he usado programación funcional en años y recientemente comencé a mirarla nuevamente, por lo que es posible que no esté completamente en lo cierto aquí.:)

Una cosa que no había visto realmente enfatizada aquí es que los lenguajes funcionales modernos como Haskell realmente se centran más en funciones de primera clase para el control de flujo que en la recursividad explícita.No es necesario definir factorial recursivamente en Haskell, como se hizo anteriormente.creo que algo como

fac n = foldr (*) 1 [1..n]

es una construcción perfectamente idiomática y mucho más cercana en espíritu al uso de un bucle que a la recursividad explícita.

Una programación funcional es idéntica a la programación procedimental en la que las variables globales son no siendo utilizado.

Los lenguajes procedimentales tienden a realizar un seguimiento del estado (usando variables) y tienden a ejecutarse como una secuencia de pasos.Los lenguajes puramente funcionales no realizan un seguimiento del estado, utilizan valores inmutables y tienden a ejecutarse como una serie de dependencias.En muchos casos, el estado de la pila de llamadas contendrá información equivalente a la que se almacenaría en las variables de estado del código de procedimiento.

La recursividad es un ejemplo clásico de programación de estilo funcional.

Konrad dijo:

Como consecuencia, un programa puramente funcional siempre produce el mismo valor para una entrada, y el orden de evaluación no está bien definido;lo que significa que los valores inciertos como la entrada del usuario o los valores aleatorios son difíciles de modelar en lenguajes puramente funcionales.

El orden de evaluación en un programa puramente funcional puede ser más difícil de razonar (especialmente con pereza) o incluso sin importancia, pero creo que decir que no está bien definido hace que parezca que no puedes saber si tu programa está funcionando. para trabajar en absoluto!

Quizás una mejor explicación sería que el flujo de control en los programas funcionales se basa en cuándo se necesita el valor de los argumentos de una función.Lo bueno de esto es que en programas bien escritos el estado se vuelve explícito:cada función enumera sus entradas como parámetros en lugar de hacerlo arbitrariamente munando estado mundial.Entonces, en algún nivel, Es más fácil razonar sobre el orden de evaluación con respecto a una función a la vez..Cada función puede ignorar el resto del universo y centrarse en lo que necesita hacer.Cuando se combinan, se garantiza que las funciones funcionarán igual[1] que si estuvieran aisladas.

...Los valores inciertos, como la entrada del usuario o los valores aleatorios, son difíciles de modelar en lenguajes puramente funcionales.

La solución al problema de entrada en programas puramente funcionales es incorporar un lenguaje imperativo como ADSL usando una abstracción suficientemente poderosa.En lenguajes imperativos (o no puramente funcionales), esto no es necesario porque se puede "hacer trampa" y pasar el estado implícitamente y el orden de evaluación es explícito (le guste o no).Debido a esta "trampa" y evaluación forzada de todos los parámetros de cada función, en los lenguajes imperativos 1) se pierde la capacidad de crear sus propios mecanismos de flujo de control (sin macros), 2) el código no es inherentemente seguro para subprocesos y/o paralelizable por defecto, 3) e implementar algo como deshacer (viaje en el tiempo) requiere un trabajo cuidadoso (¡el programador imperativo debe almacenar una receta para recuperar los valores anteriores!), mientras que la programación funcional pura te permite comprar todas estas cosas, y quizás algunas más. lo he olvidado: "gratis".

Espero que esto no suene a fanatismo, sólo quería añadir algo de perspectiva.La programación imperativa y especialmente la programación de paradigma mixto en lenguajes potentes como C# 3.0 siguen siendo formas totalmente efectivas de hacer las cosas y No hay bala de plata.

[1]...excepto posiblemente con respecto al uso de la memoria (cf.foldl y foldl' en Haskell).

Para ampliar el comentario de Konrad:

y el orden de evaluación no está bien definido

Algunos lenguajes funcionales tienen lo que se llama evaluación diferida.Lo que significa que una función no se ejecuta hasta que se necesita el valor.Hasta ese momento, la función en sí es lo que se transmite.

Los lenguajes procesales son paso 1 paso 2 paso 3...si en el paso 2 dices sumar 2 + 2, lo hace en ese momento.En una evaluación diferida se diría sumar 2 + 2, pero si el resultado nunca se usa, nunca se suma.

Si tiene la oportunidad, le recomendaría obtener una copia de Lisp/Scheme y realizar algunos proyectos en él.La mayoría de las ideas que últimamente se han convertido en tendencia se expresaron en Lisp hace décadas:programación funcional, continuaciones (como cierres), recolección de basura, incluso XML.

Así que esa sería una buena manera de tomar ventaja sobre todas estas ideas actuales, y algunas más, como el cálculo simbólico.

Debes saber para qué sirve la programación funcional y para qué no.No sirve para todo.Algunos problemas se expresan mejor en términos de efectos secundarios, donde la misma pregunta da respuestas diferentes dependiendo de cuándo se formula.

@Creighton:

En Haskell hay una función de biblioteca llamada producto:

prouduct list = foldr 1 (*) list

o simplemente:

product = foldr 1 (*)

entonces el factorial "idiomático"

fac n = foldr 1 (*)  [1..n]

simplemente sería

fac n = product [1..n]

Programación funcional

num = 1 
def function_to_add_one(num):
    num += 1
    return num


function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)

#Final Output: 2

Programación procesal

num = 1 
def procedure_to_add_one():
    global num
    num += 1
    return num


procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()

#Final Output: 6

function_to_add_one es una función

procedure_to_add_one es un procedimiento

Incluso si ejecutas el función cinco veces, cada vez volverá 2

Si ejecutas el procedimiento cinco veces, al final de la quinta ejecución te dará 6.

La programación procesal divide secuencias de declaraciones y construcciones condicionales en bloques separados llamados procedimientos que se parametrizan sobre argumentos que son valores (no funcionales).

La programación funcional es la misma excepto que las funciones son valores de primera clase, por lo que pueden pasarse como argumentos a otras funciones y devolverse como resultados de llamadas a funciones.

Tenga en cuenta que la programación funcional es una generalización de la programación procedimental en esta interpretación.Sin embargo, una minoría interpreta que "programación funcional" significa libre de efectos secundarios, lo cual es bastante diferente pero irrelevante para todos los lenguajes funcionales principales, excepto Haskell.

Para comprender la diferencia, es necesario comprender que el paradigma "padrino" de la programación tanto procedimental como funcional es el programación imperativa.

Básicamente, la programación procesal es simplemente una forma de estructurar programas imperativos en los que el método principal de abstracción es el "procedimiento". (o "función" en algunos lenguajes de programación).Incluso la Programación Orientada a Objetos es solo otra forma de estructurar un programa imperativo, donde el estado se encapsula en objetos, convirtiéndose en un objeto con un "estado actual", además este objeto tiene un conjunto de funciones, métodos y otras cosas que le permiten El programador manipula o actualiza el estado.

Ahora, en lo que respecta a la programación funcional, el esencia Su enfoque es que identifica qué valores tomar y cómo estos valores deben transferirse.(por lo tanto, no hay estado ni datos mutables, ya que toma funciones como valores de primera clase y las pasa como parámetros a otras funciones).

PD:Comprender cada paradigma de programación para el que se utiliza debería aclarar las diferencias entre todos ellos.

PD:Al final del día, los paradigmas de programación son simplemente enfoques diferentes para resolver problemas.

PD: este La respuesta de quora tiene una gran explicación.

Ninguna de las respuestas aquí muestra programación funcional idiomática.La respuesta factorial recursiva es excelente para representar la recursividad en FP, pero la mayoría del código no es recursivo, por lo que no creo que esa respuesta sea completamente representativa.

Supongamos que tiene una serie de cadenas y cada cadena representa un número entero como "5" o "-200".Desea comparar esta matriz de entrada de cadenas con su caso de prueba interno (usando comparación de enteros).Ambas soluciones se muestran a continuación.

Procesal

arr_equal(a : [Int], b : [Str]) -> Bool {
    if(a.len != b.len) {
        return false;
    }

    bool ret = true;
    for( int i = 0; i < a.len /* Optimized with && ret*/; i++ ) {
        int a_int = a[i];
        int b_int = parseInt(b[i]);
        ret &= a_int == b_int;  
    }
    return ret;
}

Funcional

eq = i, j => i == j # This is usually a built-in
toInt = i => parseInt(i) # Of course, parseInt === toInt here, but this is for visualization

arr_equal(a : [Int], b : [Str]) -> Bool =
    zip(a, b.map(toInt)) # Combines into [Int, Int]
   .map(eq)
   .reduce(true, (i, j) => i && j) # Start with true, and continuously && it with each value

Si bien los lenguajes funcionales puros son generalmente lenguajes de investigación (ya que al mundo real le gustan los efectos secundarios libres), los lenguajes procedimentales del mundo real utilizarán la sintaxis funcional mucho más simple cuando sea apropiado.

Esto generalmente se implementa con una biblioteca externa como Lodash, o disponible integrado con idiomas más nuevos como Óxido.El trabajo pesado de la programación funcional se realiza con funciones/conceptos como map, filter, reduce, currying, partial, los tres últimos de los cuales puedes consultar para una mayor comprensión.

Apéndice

Para poder usarlo en la naturaleza, el compilador normalmente tendrá que descubrir cómo convertir la versión funcional en la versión procedimental internamente, ya que la sobrecarga de llamadas a funciones es demasiado alta.Los casos recursivos como el factorial que se muestra utilizarán trucos como llamada de cola para eliminar el uso de memoria O(n).El hecho de que no haya efectos secundarios permite a los compiladores funcionales implementar la && ret optimización incluso cuando el .reduce se hace al final.El uso de Lodash en JS obviamente no permite ninguna optimización, por lo que es un impacto en el rendimiento (lo cual no suele ser una preocupación en el desarrollo web).Los lenguajes como Rust se optimizarán internamente (y tendrán funciones como try_fold para asistir && ret mejoramiento).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top