TEMA 3

Lenguaje Haskell. Estructuras complejas

1 Tipos de estructuras de datos

2 Construcción y acceso de estructuras de datos

3 Estructura de datos LISTA. Definición y Operaciones. Listas Infinitas

4 Ejemplos

 

Tipos de estructuras de datos

En Haskell vamos a diferenciar dos tipos de estructuras complejas: tuplas y listas.

Las tuplas son conjuntos o secuencias heterogéneas de elementos, con una longitud (nº de elementos), predefinida que no puede variar.

Las listas son secuencias de elementos del mismo tipo, cuya longitud puede variar e incluso, no especificarse: listas infinitas.

[Índice]

Construcción y acceso de estructuras de datos

Para construir una tupla utilizamos la sintaxis siguiente:

(t1, t2, ... , tn)

La tupla posee n elementos. Por tanto, si escribimos una función que acepte como parámetro esta tupla, necesariamente la tupla actual que sirva de argumento a una llamada a la función debe contar con n elementos exactamente. La signatura de la tupla es:

(tipo1, tipo2, ... , tipon)

Por ejemplo, si definimos la suma entre pares de elementos el código de la función quedaría del modo que sigue:

suma::(Int, Int)->Int

suma (x, y)=x+y

Esta función es completamente distinta de aquella que suma dos números:

suma::Int->Int->Int

suma x y=x+y

La primera acepta una tupla de dos elementos enteros mientras que la segunda acepta dos números enteros independientes no agrupados en estructura compleja alguna.

Otra estructura compleja muy utilizada es la LISTA, que vamos a describir detalladamente en la sección siguiente.

[Índice]

Estructura de datos LISTA. Definición y Operaciones. Listas Infinitas

Como ya hemos comentado, una lista se puede definir como una secuencia de elementos del mismo tipo. Por ejemplo [1,2,-3,0] constituye una lista de elementos enteros. Una función que acepta como parámetro una lista, puede trabajar con un argumento actual de cualquier longitud, siempre que los elementos sean del tipo especificado en la signatura, en el caso de que aparezca, y la lista sea homogénea.

Las listas se pueden representar de formas diversas, como ocurría en Prolog:

Para realizar operaciones con listas en Haskell debemos acoger el método que usábamos en Prolog: recursividad. Recordemos que recursividad y backtraking no son lo mismo, así pues, en Haskell no aparece la idea de backtracking en la ejecución de los programas.

La sintaxis para especificar los datos de una lista es variada:

Haskell proporciona un conjunto de funciones predefinidas para el manejo de listas:

También proporciona una sintaxis de contrucción de listas muy potente: Listas de Números y List Comprehension.

[Índice]

Listas de Números

Como en otros lenguajes funcionales podemos utilizar una notación especial para las listas de números donde la diferencia entre elementos consecutivos es constante

Para las listas donde la diferencia no es 1, la notación es [m,k..n], siendo m el primer elemento de la lista, k el segundo, los siguientes se diferencian entre ellos lo mismo que m y k y ningún elemento de la lista puede ser mayor que n. Por ejemplo [2,4..10] es lo mismo que [2,4,6,8,10].

[Índice]

List Comprehension

La notación List Comprehension es similar a la utilizada en matemáticas para construir conjuntos, y puede ser muy útil a la hora de construir ciertos tipos de listas. La sintaxis es como sigue:

[expresion|calificador,calificador,...]

Con esta expresión se genera una lista donde los elementos son de la forma de expresion y cumplen las condiciones expresadas en los calificadores.

La expresión puede ser cualquier expresión válida y los calificadores pueden ser de 3 tipos: generadores, filtros y definiciones locales.

Veamos algunos ejemplos de construcción de listas:

[n|n<-[1..5]] Þ [1,2,3,4,5]

[n*n|n<-[1..5]] Þ [1,4,9,16,25]

[n|n<-[1..5], par n] Þ [2,4]

[(n, n*n)|n<-[1..3], n<n*n] Þ [(2,4),(3,9)]

[n*n|n=2] Þ [4]

[1|n<-[1..5]] Þ [1,1,1,1,1]

[(i,j)|i<-[1..2], j<-[1..2]] Þ [(1,1), (1,2), (2,1), (2,2)]

[Índice]

Ejemplos

Para entender adecuadamente lo expuesto en los puntos anteriores, veamos algunos ejemplos interesantes de manejo de listas.

Ejemplos

Ejemplos que ilustran la utilización de listas.

Función que me dice si un número es o no primo.

divisores Int->[Int]

divisores n=[d|d<-[1..n], n ‘mod’ d==0]

primo Int->Bool

primo n=(divisores n==[1,n])

Función que devuelve el nésimo elemento de una lista.

enesimo Int->[Int]->Int

enesimo 1 (c:cola)=c

enesimo n (c:cola)=enesimo(n-1) cola

Función que invierte una lista.

invertir [Int]->[Int]

invertir []=[]

invertir (c:cola)=invertir cola++[c]

 [Índice]