TEMA 2

Lenguaje Haskell. Conceptos y Estructuras básicas

1 Sintaxis básica de Haskell

1.1 Tipos de datos

1.2 Operandos y operaciones

1.3 Aritmética y comparaciones

1.4 Evaluación de funciones

1.5 Ejemplos

Sintaxis básica de Haskell

En un lenguaje funcional, un programa consistirá en evaluar una función. Por tanto, veamos como se realiza la evaluación de funciones en un lenguaje funcional particular: Haskell.

En este capítulo vamos a estudiar los tipos de datos que podemos usar, los operandos y operaciones así como su aritmética.

Todo ello se ilustrará con los correspondientes ejemplos en el último punto.

[Índice]

Tipos de datos

En la Tabla 1 se muestran los distintos tipos que ofrece el lenguaje.

Tipo

Descripción

Int

Entero: 2, 3, -1, 0, ...

Float

Real: 0.5, 1, -0.45, ...

Char

Carácter: ‘a’, ‘b’, ‘F’, ...

Bool

Booleano: ‘true’ o ‘false’

Tabla 1

También podemos tener cadenas de caracteres que se pueden definir como listas de caracteres, las cadenas de caracteres se escriben mediante comillas dobles: "hola".

La forma de escribir una función en Haskell se define a continuación:

En la definición de la signatura se utiliza la siguiente sintaxis:

nombre_funcion::tipo_argumento->tipo_resultado

En la definición del cuerpo de la función la sintaxis es como sigue:

nombre_funcion nombre_argumento=<implementacion>

Ejemplo de un programa que calcula el doble de un número entero

doble::Int->Int

doble x=2*x

 

En principio, la signatura puede omitirse de forma que el sistema haga inferencia sobre los tipos. Recordemos que estamos trabajando en un sistema de tipos fuerte.

En este lenguaje funcional se puede utilizar la sentencia condicional IF del modo siguiente:

if <expresion1> then <expresion2> else <expresion3>

Para realizar bucles y otros tipos de estructuras de control, usaremos el concepto de recurrencia.

Ejemplo de programas que comprueban si un número es, o no, par

par::Int->Bool

par x=(x ‘mod’ 2)==0

par::Int->Bool

par x=if (x ‘mod’ 2)==0 then True else False

 

Además en Haskell se pueden definir tipos generales, de la forma siguiente: identidad::a->a es más general que identidad::Int->Int ya que a es un tipo que abarca muchas más instancias que el tipo Int.

Por otro lado, ningún nombre de variable puede aparecer más de una vez en la parte izquierda de cada ecuación en la definición de una función. Por tanto, no podemos definir funciones del tipo:

iguales x x = True

iguales __=False

Podemos utilizar la siguiente notación cuando necesitemos que los argumentos de una función cumplan ciertas condiciones:

iguales x y

|x==y = True

|otherwise = False

En general esta notación se usa de la forma siguiente:

funcion x1 x2 ... xn

|condicion1 =e1

|condicion2 =e2

...

|condicionm =em

|otherwise =eotros

[Índice]

Operandos y operaciones

La Tabla 2 muestra el tipo de operaciones que se pueden realizar, el número de operandos que corresponden a cada operación y el operador que se utiliza en cada caso.

Operaciones entre números

suma

+

2 operandos en todas las operaciones de este tipo

resta

-

multiplicacion

*

división entera

‘div’

resto

‘mod’

división

/

Operaciones booleanas

True, False

True y False no se aplican sobre operandos. AND y OR se aplican sobre dos operandos y NOT sobre un operando

AND

&&

OR

||

NOT

not

Operaciones entre caracteres

Obtener carácter

chr

Se aplican sobre un operando

Obtener Código ASCII

ord

Tabla 2

[Índice]

Aritmética y comparaciones

En el lenguaje Haskell tenemos un conjunto de operadores relacionales que se especifican a continuación, en la Tabla 3.

Tipo

Descripción

==

Igual

/=

Distinto

<

Menor

>

Mayor

<=

Menor o igual

>=

Mayor o igual

Tabla 3

Evaluación de funciones

Podemos definir las funciones en Haskell de varios modos. Veamos detenidamente cada uno de ellos.

Composición de funciones. Función aplicable sobre un argumento que es otra función. Primero se evalúa la función del argumento y, posteriormente, con el resultado obtenido, la composición es evaluada.

Patter Machine. Las funciones se pueden definir de varios modos. Esto implica que la forma de evaluación de las mismas se hará mediante Patter Machine. El intérprete buscará de arriba abajo en el conjunto de definiciones de una función aquella que concuerde con la llamada especificada.

Currificación. Dada la función f x y, f se aplica sobre el primer argumento, es decir, sobre x resultando una función f’ que se aplica sobre el segundo argumento y.

El tipo de funciones que vamos a usar en Haskell es no estricto. Recordemos que una función no estricta es aquella que posee evaluación perezosa. Si aplicamos una función estricta sobre una expresión que falla o no termina, la función también falla. Con las funciones no estrictas, en cambio, no sucede dicho fallo. Por ejemplo, si tenemos la función

constante Int->Int

constante x=1

En un lenguaje estricto la llamada constante(1/0) fallaría, sin embargo, en un lenguaje no estricto devuelve 1.

[Índice]

Ejemplos

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

Ejemplos

Ejemplo que ilustra la utilización de los tipos polimórficos o genéricos.

identidad::a->a

identidad x=x

Ejemplo que ilustra la composición de funciones.

doble Int->Int

doble x=2*x

par Int->Bool

par x=(x ‘mod’ 2)==0

?.-par doble 3

Ejemplo que ilustra la utilización del Pattern Machine.

factorial Int->Int

factorial 0=1

factorial x=x*factorial(x-1)