2. Modelo de programación Funcional


Modelo de Programación Funcional – IT Tehuacán

Instituto Tecnológico de Tehuacán

Ingeniería en Sistemas Computacionales | Programación Lógica y Funcional

Tema: El Modelo de Programación Funcional

1. Introducción al Modelo de Programación Funcional

El Modelo de Programación Funcional es un paradigma declarativo basado en el concepto matemático de función y en las reglas del Cálculo Lambda (λ) desarrollado por Alonzo Church en la década de 1930. A diferencia de la programación imperativa, no maneja estados mutables ni secuencias de instrucciones de control de flujo explícitas (como bucles for o while).

Importancia Estratégica del Paradigma
En la era moderna del hardware multinúcleo y el procesamiento masivo de datos (Big Data), la programación funcional es fundamental. Al eliminar el estado mutable y los efectos secundarios, el código funcional es intrínsecamente seguro para la concurrencia y el paralelismo, evitando bloqueos (deadlocks) y condiciones de carrera (race conditions).

Transparencia Referencial

Una expresión o función siempre produce el mismo resultado dado el mismo argumento. Puede ser reemplazada por su valor sin alterar el programa.

Inmutabilidad

Las variables son constantes. Un valor asignado nunca cambia; para «modificar» un dato se genera una nueva estructura en memoria.

Ausencia de Efectos Secundarios

Las funciones puras no alteran el estado global, no modifican variables de entrada ni interactúan con I/O fuera de su ámbito delimitado.

2. Tipos de Datos en Lenguajes Funcionales

En lenguajes como Haskell, el sistema de tipos es estático y fuertemente tipado con un potente motor de Inferencia de Tipos (Hindley-Milner).

Categoría Tipo en Haskell Descripción y Ejemplos
Tipos Primitivos Int, Integer, Float, Double, Bool, Char Valores atómicos. Integer ofrece precisión infinita (limitada solo por la RAM).
Estructuras Compuestas Listas ([a]), Tuplas ((a, b)) Las listas son homogéneas; las tuplas son heterogéneas y de tamaño fijo.
Tipos Algebraicos (ADT) data / type Permite crear tipos personalizados sum/product (Ej. data Bool = False | True).
3. Funciones: Conceptos Clave

Las funciones en programación funcional son ciudadanos de primera clase (First-class citizens) y soportan abstracciones avanzadas:

A. Currificación (Currying)

Toda función en Haskell toma técnicamente un solo argumento. Funciones con múltiples parámetros son evaluadas como una cadena de funciones anidadas de un argumento.

-- Suma expresada normalmente (Currificada por defecto en Haskell)
suma :: Int -> Int -> Int
suma x y = x + y

-- Ocurre equivalencia con: suma x = \y -> x + y
B. Funciones de Alto Orden (Higher-Order Functions)

Son aquellas que reciben funciones como parámetros o devuelven funciones como resultado.

-- Uso de map (Alto orden) para duplicar una lista
duplicarLista :: [Int] -> [Int]
duplicarLista xs = map (\x -> x * 2) xs
C. Composición de Funciones

Combina dos o más funciones mediante el operador punto (.), equivalente al operador matemático (f o g)(x) = f(g(x)).

cuadrado :: Int -> Int
cuadrado x = x * x

incrementar :: Int -> Int
incrementar x = x + 1

-- Composición: primero incrementa, luego calcula cuadrado
operacionCompuesta :: Int -> Int
operacionCompuesta = cuadrado . incrementar  -- operacionCompuesta 4 = 25
4. Intervalos (Ranges) y Operadores

Los Intervalos permiten generar secuencias aritméticas de forma concisa empleando la notación [inicio..fin] o secuencias infinitas [inicio..].

-- Ejemplos de Intervalos
numeros = [1..10]          -- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pares = [2, 4..20]          -- [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
abecedario = ['a'..'z']     -- Lista de caracteres
infinito = [1..]            -- Lista infinita de enteros
Operadores Principales sobre Listas e Intervalos
Operador / Función Sintaxis Descripción Ejemplo y Resultado
Cons (Construcción) : Agrega un elemento al inicio de una lista. 1 : [2, 3][1, 2, 3]
Concatenación ++ Une dos listas homogéneas. [1, 2] ++ [3, 4][1, 2, 3, 4]
Indexación !! Obtiene el n-ésimo elemento (base 0). [10, 20, 30] !! 120
Cabeza / Cola head / tail head obtiene el 1er elemento; tail el resto. head [1,2,3]1
5. Aplicaciones de las Listas y List Comprehensions

Las listas son la estructura de datos recursiva fundamental en programación funcional. Una herramienta de alta potencia son las Listas por Comprensión (basadas en la notación matemática de conjuntos).

Sintaxis: [ expresión | generador, filtro1, filtro2 ]

Lee: «Construir la lista con la expresión para cada valor del generador que cumpla las condiciones de los filtros«.

-- Ejemplo 1: Cuadrados de números pares entre 1 y 20
cuadradosPares = [x^2 | x <- [1..20], x `mod` 2 == 0]

-- Ejemplo 2: Algoritmo Quicksort expresado concisamente con List Comprehension
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (pivote:resto) = 
    quicksort [x | x <- resto, x <= pivote] 
    ++ [pivote] 
    ++ quicksort [x | x <- resto, x > pivote]
6. Estructuras No Lineales: Árboles

En el paradigma funcional, estructuras avanzadas como los Árboles Binarios se modelan mediante Tipos de Datos Algebraicos Recursivos.

-- Definición de un Árbol Binario de Búsqueda (BST)
data Arbol a = Vacio 
             | Nodo a (Arbol a) (Arbol a)
             deriving (Show, Eq)

-- Función para insertar un elemento en el árbol
insertar :: Ord a => a -> Arbol a -> Arbol a
insertar x Vacio = Nodo x Vacio Vacio
insertar x (Nodo val izq der)
    | x == val  = Nodo val izq der
    | x < val   = Nodo val (insertar x izq) der
    | otherwise = Nodo val izq (insertar x der)
Esquema Gráfico del Árbol Binario
Raíz: Nodo 10 / \ Nodo 5 Nodo 15 / \ / \ Vacio Vacio Vacio Vacio
7. Evaluación Perezosa Paso a Paso

La Evaluación Perezosa (Lazy Evaluation) o reducción mediante Call-by-Need retrasa el cálculo de una expresión hasta que su resultado es estrictamente indispensable para el progreso del programa.

Paso a Paso: Traza de Evaluación

Supongamos la función doble x = x + x y la expresión take 2 (map doble [1..]):

Paso 1: Petición Externa

take 2 requiere únicamente los primeros 2 elementos de la lista infinita.

Paso 2: Generación Demanda

El intervalo [1..] genera solo el valor 1. Se aplica doble 12.

Paso 3: Segundo Elemento

El intervalo genera 2. Se aplica doble 24.

Paso 4: Detención

take 2 se satisface con [2, 4]. El resto de la lista infinita NUNCA se evalúa en RAM.

8. Ejercicios Prácticos Resueltos
Ejercicio 1 (Listas e Intervalos): Escribir una función que reciba un número n y devuelva la suma de los cuadrados de todos los números impares desde 1 hasta n.
sumaCuadradosImpares :: Int -> Int
sumaCuadradosImpares n = sum [x^2 | x <- [1..n], odd x]

-- Ejemplo de uso: sumaCuadradosImpares 5 -> 1^2 + 3^2 + 5^2 = 35
Ejercicio 2 (Árboles Binarios): Escribir una función recursiva sumarArbol que calcule la suma total de los valores de un árbol de enteros.
sumarArbol :: Arbol Int -> Int
sumarArbol Vacio = 0
sumarArbol (Nodo v izq der) = v + sumarArbol izq + sumarArbol der
Ejercicio 3 (Evaluación Perezosa): Definir una lista infinita que contenga todos los números de Fibonacci utilizando zipWith.
fibs :: [Integer]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

-- Para obtener los primeros 10: take 10 fibs
9. Examen de Conocimientos (15 Preguntas)

Responde el siguiente cuestionario para evaluar tu comprensión sobre la materia:

1. ¿En qué teoría matemática se fundamenta principalmente la Programación Funcional?

2. ¿Qué garantiza la Transparencia Referencial?

3. ¿Qué ocurre con los datos cuando se maneja la Inmutabilidad?

4. El concepto de Currificación (Currying) implica que:

5. ¿Cuál es la diferencia entre una Lista y una Tupla en Haskell?

6. ¿Qué operador en Haskell inserta un elemento al inicio de una lista?

7. La evaluación perezosa (Lazy Evaluation) evalúa las expresiones cuando:

8. ¿Qué permite hacer la Evaluación Perezosa con respecto a las estructuras de datos?

9. ¿Qué operador se utiliza para la composición de funciones en Haskell?

10. Una Función de Alto Orden es aquella que:

11. ¿Qué resultado produce la expresión `head [5, 10, 15]`?

12. ¿Cómo se definen generalmente las estructuras no lineales como los Árboles en programación funcional?

13. ¿Qué sintaxis en Haskell define el intervalo de números pares entre 2 y 10?

14. ¿Cuál es una de las ventajas principales de eliminar los efectos secundarios en entornos concurrentes?

15. ¿Qué realiza la función `tail [1, 2, 3, 4]`?