La programación funcional es un paradigma declarativo que usa funciones como “ciudadanas de primera clase”. Las funciones (en programación) son fragmentos de código reutilizables, que pueden recibir datos y dar salidas a otros datos como resultado, incluyendo otras funciones. Mediante la programación funcional se busca eliminar o reducir los efectos secundarios.
En la programación funcional se pueden crear funciones de orden superior (HOF). Prioriza el uso de recursividad y HOF para resolver problemas.
Origen de la programación funcional
En los años 30, Alonzo Church desarrolló el cálculo Lambda. Alan Turing demostró que este es equivalente a las máquinas de Turing. A finales de los 50, se desarrolló LISP, implementando la notación lambda de Church. Aquí un ejemplo en LISP de cómo se ve un “hola mundo” y una función recursiva (que se llama a sí misma) donde se calcula el factorial de un número n
.
(print "Hello, World!")
(defun factorial (n)
(if (= n 0) 1
(* n (factorial (- n 1)))))
Funciones
En matemáticas, una función se define como una relación entre dos conjuntos que asigna cada elemento del primero, un elemento del segundo o ninguno.
Por ejemplo, una función que toma un valor “X” y genera un valor “Y”.
f(X) = X + 3
f(X) = X^2 + 3
Un ejemplo de funciones en Python es el siguiente. La función suma recibe dos números (a y b) y retorna la suma de los dos números. Aquí podemos ver que el concepto de función en matemáticas y en programación es parecido.
def suma (a, b):
return a + b
operacion_1 = suma(3, 2)
Las funciones también pueden hacer uso de otras funciones, como en el siguiente ejemplo.
def es_par(x):
return not es_impar(x)
Es más, las funciones pueden llamarse a sí mismas (recursión)
def fibonacci(n):
if n<=1:
return m
else:
return fibonacci(n-1)+fibonacci(n-2)
Conceptos de la programación funcional
Al principio mencionamos conceptos como “ciudadanas de primera clase”, funciones de orden superior y efectos secundarios. Definamos estos (y más) conceptos.
Funciones como ciudadanas de primera clase
El que las funciones sean ciudadanas de primera clase implica que son reconocidas como un tipo de dato más. Esto hace que se puedan usar en cualquier parte del programa.
Funciones de orden superior
Una función de orden superior puede recibir una o varias funciones como parámetro. Además, puede retornar otra función.
Funciones puras
Una función es pura si cumple con los siguientes requisitos.
- Es determinista: para un parámetro, la función siempre va a retornar el mismo resultado siempre y cuando no se cambie dicho parámetro (por ejemplo, una función que retorne un valor aleatorio no es determinista).
- Un valor de entrada da un solo valor de salida.
- No genera efectos secundarios.
- No incluye funciones impuras.
Funciones lambda
Una función lambda es una función anónima, es decir, que no se le asigna un nombre. Normalmente, se usan en una única sección del código. Por lo general realizan operaciones simples.
Un ejemplo de una función lambda que multiplica dos números en Python:
x = lambda a, b: a**b
print(x(3,3))
Efectos secundarios (side effects)
Es común escuchar de efectos secundarios cuando hablamos de programación imperativa. Lo podemos ver cuando manejamos funciones o variables de contexto global o que están delimitadas. Cuando escribimos código sabemos que lo que está dentro de una función, no afecta a otra, si es que usamos la sintaxis correcta. Pero también existen funciones que usan parámetros o que tienen alcance global y pueden tener efectos secundarios.
Los efectos secundarios son cambios observables en partes de un programa como:
- El estado de la aplicación.
- Valores de datos.
- Modificación de archivos.
Lenguajes y ejemplos
Este es un ejemplo en Haskell, donde calculamos el factorial de un número. En ejemplos anteriores habíamos podido ver como se define el tipo de dato, después se asignan los tipos de valores y se empieza a llamar a la función. Podemos ver que el código no es tan amplio como si lo hubiéramos escrito de forma no recursiva con otros lenguajes.
module Main where
import Text.Printf
factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n factorial (n - 1)
line x = printf "%d! = %d\n" x $
factorial x
main = mapM_ line [0..16]
Aquí otro ejemplo con F#, donde vemos que también es recursivo porque la función factorial se llama a sí misma.
let rec factorial n =
match n with
| 0 | 1 -> 1
| _ -> n * factorial(n-1)
Otros lenguajes funcionales son SCHEME, CLOJURE, RACKET y ERLANG.
Conclusión
La programación funcional nos permite escribir código especificando qué queremos hacer más que cómo se debe hacer. A su vez, nos permite evitar efectos secundarios. Es importante entender conceptos como funciones de orden superior, recursividad o funciones puras para poder hacer un buen uso de la programación funcional.
Contribución creada por: Ciro Villafraz con los aportes de Iris Valentina.
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?