Funciones Recursivas

Una función recursiva, al igual que en los lenguajes imperativos, es una función que se llama a si misma.
En toda función recursiva debe haber un caso base y uno o varios casos recursivos.

Por ejemplo, si implementamos la función factorial de forma recursiva, sería de la siguiente forma:

factorial :: Int -> Int
factorial 0 = 1
factorial (n + 1) = (n + 1) * factorial n

En esta función además de recursividad estamos aplicando patrones constantes y aritméticos(explicado en parte 2).

Otra manera de resolver este ejercicio sería usando un parámetro extra que acumule el valor del factorial:

factorial :: Int -> Int -> Int
factorial 0 _ = 1
factorial 1 acumulado = acumulado
factorial n acumulado = factorial (n-1) (acumulado*n)

La llamada inicial sería, por ejemplo:

factorial 4 0 = factorial 3 4 = factorial 2 12 = factorial 1 24 = 24

Le hemos añadido la regla “0 _ = 1” para que en caso de que se haga la llamada

factorial 0 0

no falle y devuelva el valor 1.


Funciones de orden superior

Consiste en pasar funciones a otra función como parámetro. Esto es algo que en los lenguajes imperativos tradicionales resulta impensable. Sin embargo se da en algunos lenguajes híbridos como JavaScript, Python, Scala …

f1 :: Int -> Int
f1 x = operación que usa x

f2 :: (Int -> Int) -> Int -> Int
f2 f x = x + f x

Con la expresión entre paréntesis “(Int -> Int)” le estamos indicando que recibirá una funcion que a su vez recibe un entero y devuelve otro entero.
Se hará la llamada de la forma:

f2 f1 5

En este caso la función f2 devolverá la suma de 5 + el resultado de f1(5).

Funciones de orden superior predefinidas:

– map: esta función recibe una función y una lista, y devuelve otra lista cuyos elementos son el resultado de aplicar la función recibida a todos los elementos de la lista recibida.

Por ejemplo si hacemos la llamada:

map length [“jjj”, “kk”, “i”]

devolverá

[3, 2, 1]

– all: comprueba si todos los elementos de la lista cumplen una propiedad

all even [2, 4, 6] = True

sin embargo

all even [2, 4, 5] = False

– any: comprueba si alguno de los elementos de la lista cumplen la propiedad

any even [2, 4, 5] = True

sin embargo

any even [1, 3, 5] = False

– foldr: pliega la lista por la derecha en función de la operación que reciba, un valor inicial y la lista.

Por ejemplo si queremos que se multipliquen todos los valores de una lista, se podría hacer recursivamente:

multiLista :: [Int] -> Int
multiLista [] = 1
multiLista (x:xs) = x * multiLista xs

Pero esto también se puede realizar con foldr de forma sencilla:

multiLista :: [Int] -> Int
multiLista = foldr (*) 1

En esta función se esta pasando automáticamente la lista a foldr (visto en parte 2), y se esta dando como valor inicial el del caso base “1” cuando la lista está vacía.
La ejecución sería:

multilista [2, 3, 4] = foldr (*) 1 [2, 3, 4] = (2 *(3 *(4 * 1))) = 24

– foldl: es igual que foldr pero realiza el plegado por la izquierda.

multiLista :: [Int] -> Int
multiLista = foldl (*) 1

multilista [2, 3, 4] = foldl (*) 1 [2, 3, 4] = (((2 * 1)* 3)* 4) = 24

En este caso el resultado es igual porque la multiplicación cumple las propiedades conmutativa y asociativa. Sin embargo si el operador que le pasáramos a foldr o foldl como argumento fuera una función los resultados serían distintos.


Expresiones lambda

Las funciones lambda se usan en Haskell para instanciar funciones anónimas (incorporadas en lenguajes como Java). Las funciones lambda se encuentran en otros lenguajes como Scala y Python.

En Haskell la sintaxis es:

\variable recibida -> operación sobre la variable

Estas se usan para declarar funciones de un solo uso. Por ejemplo:

map (\x -> x + 2) [1, 2, 3, 4] = [3, 4, 5, 6]

En vez de tener que hacer uso de las definiciones locales, con las cuales sería de la forma (explicado en parte 2):

map f [1, 2, 3, 4] where f x = x + 2


Polimorfismo

Esta característica la tienen multitud de lenguajes debido a la facilidad de reutilización de código y genericidad de los mismos.
Consiste en que, por ejemplo, podamos declarar una función que reciba una lista de cualquier tipo, y nos devuelva su longitud:

longitud :: [a] -> Int
longitud [] = 0
longitud (x:xs) = 1 + longitud xs

La lista recibida podría ser una lista de tipo entero, un String, una lista de booleanos o cualquier tipo de lista. La función se comportará igual.
Hay que tener cuidado en usarlo solo para funciones que se puedan aplicar a cualquier tipo de dato, ya que si por ejemplo creamos una función:

multiLista :: [a] -> Int
multiLista (x:xs) = x * multiLista xs

y realizadmos la llamada

multiLista [True, False, False]

el programa fallará.

Próximamente la parte 4.

Categorías: Sin categoría

Entradas relacionadas

Sin categoría

Proxy en OpenSUSE

Ultimamente comienzo mis andanzas por Suse, un poco coñazo porque estoy hecho a Debian y derivadas (Ubuntu y cia.), y alguna vez he usado CentOS y familia y poco mas. Y cual es el problema Leer más…

Sin categoría

Abrir puertos en una máquina virtual de Azure

Con el cambio del portal clásico al nuevo portal de Azure, aveces puede resultar difícil hacer algo tan básico como abrir los puertos de una máquina virtual. Y ya que la documentación de Microsoft es Leer más…

Sin categoría

Proyecto MuSync – Alternativa Spotify

MuSync es un proyecto que nace con el objetivo personal de reemplazar Spotify en mis dispositivos. Actualmente tengo una enorme dependencia del servicio freemium de Spotify y ya no hago acopio en formato mp3 de las Leer más…

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies