Está en la página 1de 16

Apunte Laboratorio ALPI *

Pablo Speciale

Anlisis de Lenguaje de Programacin I - Universidad Nacional de Rosario

NDICE G ENERAL

NDICE G ENERAL

4.2. Nmeros enteros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

4.3. Nmero en punto flotantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

4.4. Caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

1.1. Valores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4.5. Tipos de Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19

1.2. Expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4.6. Listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19

1.3. Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4.7. Cadenas (String) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

20

1.4. Ecuaciones orientadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4.8. Enumeraciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21

1.5. Algunas definiciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4.9. Tuplas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

1.6. Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4.10. Polimorfismo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

ndice
1. Conceptos Importantes

2. Sintaxis de Haskell

5. Ms sobre funciones

24

2.1. Case sensitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5.1. Funciones annimas (lambda abstracciones) . . . . . . . . . . . . . . . . . . . . . . . .

24

2.2. Comentarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5.2. Currificacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

2.3. Definiciones de Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5.2.1. Forma prctica de ver la Currificacin . . . . . . . . . . . . . . . . . . . . . . .

27

2.4. Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5.3. Composicin de Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27

2.4.1. Identificadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5.4. Funciones totales y parciales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

2.4.2. Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.4.3. Relacin entre identificadores y operadores . . . . . . . . . . . . . . . . . . . .

2.4.4. Definiciones de Funciones con Pattern Matching . . . . . . . . . . . . . . . . .

2.4.5. Definiciones con Guardas . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.4.6. Definiciones recursivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.4.7. Definiciones locales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.4.8. Expresiones case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

2.4.9. Aplicacin de Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

2.5. Secciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

2.6. Tabla de precedencia/asociatividad de operadores . . . . . . . . . . . . . . . . . . . . .

11

2.7. Disposicin del cdigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

3. Cosas sobre el Hugs

13

3.1. Prelude.hs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

3.2. Iniciando Hugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

3.3. Comandos de Hugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

3.4. Un programa en Haskell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

4. Tipos de Haskell
4.1. Booleanos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16
16

6. Evaluacin

29

6.1. Reduccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

6.2. Evaluacin perezosa (o Lazy) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

1.4. E CUACIONES

1.

ORIENTADAS

Conceptos Importantes

1. C ONCEPTOS I MPORTANTES

1.4. Ecuaciones orientadas

En esta seccin se explica que es un lenguaje funcional puro. Adems, se dan algunas definiciones
que son la esencia de Haskell.
Expresion a def inir = Expresion def inida

1.1.

e1 = e2

Valores

Entidades matemticas abstractas con ciertas propiedades. Una expresin denota un valor. Entre las
clases de valores que una expresin puede denotar, se incluyen: nmeros de varios tipos (Int, Integer,
Float, etc.), caracteres, funciones y listas. Observar que, en Haskell, las funciones tambin son valores.

1.2.

Visin denotacional: se define que el valor denotado por e1 es el mismo que el denotado por e2 .
Visin operacional: para calcular el valor de una expresin que contiene a e1 , se puede reemplazar
e1 por e2 .

Expresiones
Nota

Cadenas de smbolos utilizados para denotar valores


Expresiones atmicas: llamadas tambin formas normales. Por abuso de notacin, les decimos
valores.

Dada una expresin bien formada, determinamos el valor que denota mediante ecuaciones. Y calculamos el valor de la misma, reemplazando subexpresiones, de acuerdo con las reglas dadas por las
ecuaciones, a sto se lo llama reduccin (ver seccin 6).

Expresiones compuestas: se arman combinado subexpresiones. Por abuso de notacin, slo les
decimos expresiones.

1.5. Algunas definiciones


Funcin de alto orden: una funcin que recibe otra funcin como argumento, o la retorna como resultado.

Notas
1. No confundir entre valores y su representacin (mediante expresiones). Pueden existir muchas formas de representar un mismo valor. Por ejemplo, 5 101 (en binario) V (en nmeros Romanos).
2. Una expresin est bien formada si cumple con las reglas sintcticas y reglas de asignacin de
tipo.
3. Algunos valores no tienen representacin cannica, por ejemplo, los valores funcionales.

1.3.

Funciones

Visin denotacional: una funcin es un valor matemtico que relaciona cada elemento de un conjunto (de partida) con un nico elemento de otro conjunto (de llegada).
Visin operacional: una funcin es un mecanismo que dado un elemento del conjunto de partida,
calcula el elemento correspondiente del conjunto de llegada.

Transparencia Referencial: el valor de una expresin depende slo de los elementos que la constituyen.
Una definicin ms informal, cuando dos cosas son iguales que sean iguales en todas partes. Por ejemplo,
en C, uno puede hacer lo siguiente:
x = x + 1;
Se le asigna a x el valor de x+1. Este ejemplo muestra un lenguaje que no posee la importante propiedad
de Transparencia Referencial, pues x no vale lo mismo antes y despus de la asignacin. Un lenguaje
as se dice que posee Efectos colaterales.
La Transparencia Referencial implica:
Abstraccin de detalles de ejecucin.
Posibilidad de demostrar propiedades usando las propiedades de las subexpresiones y mtodos de
deduccin lgicos.

Extensionalidad
Este principio recibe el nombre de principio de extensionalidad.
f =g

fx=gx

Lenguaje funcional puro: lenguaje de expresiones con transparencia referencial y funciones de alto orden, cuyo modelo de cmputo es la reduccin realizada mediante el reemplazo de igualdad por igualdad.
Haskell es un lenguaje funcional puro.

1.6. T IPOS

1.6.

DE

H ASKELL

2. Sintaxis de Haskell

Tipos

Conjunto de valores con propiedades comunes. Los tipos denotan conjuntos de valores.
Tipado Fuerte (strong typing): toda expresin debe tener un tipo para ser vlida.
Notacin:

2. S INTAXIS

e :: A

se lee

En esta seccin se muestra lo esencial de la sintaxis de Haskell.

2.1. Case sensitive

la expresin e tiene tipo A.

La sintaxis de Haskell diferencia entre maysculas y minsculas. Se dice que es Case sensitive.

Significa el valor denotado por e pertenece al conjunto de valores denotado por A.

2.2. Comentarios

Inferencia de tipos:
Dada un expresin e, determinar si tiene tipo o no segn las reglas, y cul es ese tipo

1.

Los comentarios empiezan con -- (dos menos). Por ejemplo:

Algunas reglas de inferencia de tipo:


si e1 :: A y e2 :: B

Chequeo de tipos:

si

m, n :: Int

si

d = e y e :: A

-- Este es un comentario, cuando empieza con "--"


-- Haskell (ms precisamente Hugs o ghc) lo ignora

(e1 , e2 ) :: (A, B)
m + n :: Int
d :: A

(e, A) Bool

2.3. Definiciones de Variables


La definicin de una variable tendr la forma

Dada una expresin e y un tipo A, determinar si e :: A segn las reglas.

nombre_variable :: Tipo
nombre_variable = expresion
como en el ejemplo
size :: Integer
size = 12 + 13

2.4. Funciones
Existen dos formas de nombrar una funcin, mediante un identificador (por ejemplo, sum, product
y fact), o mediante un smbolo de operador (por ejemplo, * y +)
2.4.1.

Identificadores

Los identificadores de variables o funciones deben comenzar con una letra minscula, seguido, opcionalmente por una secuencia de caracteres, cada uno de los cuales es: una letra, un dgito, un apstrofe
() o un guin bajo (_). Los siguientes son ejemplos posibles de identificadores:
sum

fintSum

nombre_con_guiones

Los siguientes identificadores son palabras reservadas y no pueden utilizarse como nombres de funciones o variables:

Devuelve el tipo ms general, es decir, el tipo con ms variables de tipos

case
of
then
else
infixr class

where
let
in
data
type
infix
instance primitive

if
infixl

2.4. F UNCIONES

2.4.2.

Operadores

2. S INTAXIS

2.4.5.

Algunas funciones se escriben entre sus (dos) argumentos en lugar de precederlos. A una funcin
escrita usando la notacin infija se le llama un operador. Por ejemplo,
3 <= 4

en lugar de

!
?

#
@

%
\

&
|

*
-

<

Definiciones con Guardas

minimo
:: (Integer, Integer) -> Integer
minimo (x,y) | x <= y
= x
| otherwise = y

menorIgual 3 4

H ASKELL

Otro modo de expresar esencialmente la misma definicin de minimo es escribir:

Un smbolo de operador es escrito utilizando uno o ms de los siguientes caracteres:


:
>

DE

Esta forma de definicin utiliza ecuaciones con guardas. Cada clusula consiste en una condicin, o
guarda, y en una expresin separada de la guarda por un signo de igualdad (=). En general una ecuacin
con guardas toma la forma:

Leer seccin 1.4.3 del libro.


2.4.3.

f x1 x2 ... xn | condicion1 = e1
| condicion2 = e2
.
.
.
| condicionm = em

Relacin entre identificadores y operadores

Se proporcionan dos mecanismos simples para utilizar un identificador como un smbolo de operador
o un smbolo de operador como un identificador:
Cualquier identificador ser tratado como un smbolo de operador si est encerrado entre comillas
inversas (). Por ejemplo,
x mod y

es equivalente a

mod x y

Cualquier smbolo de operador puede ser tratado como un identificador encerrndolo en parntesis.
Por ejemplo,
x + y
2.4.4.

es equivalente a

Leer seccin 1.5 del libro.


2.4.6.

Definiciones recursivas

Las definiciones pueden ser tambin recursivas. He aqu un ejemplo:

(+) x y

fact
:: Integer -> Integer
fact n = if n==0 then 1 else

n * fact(n-1)

Definiciones de Funciones con Pattern Matching

La declaracin de una funcin f est formada por un conjunto de ecuaciones con el formato:

Otro modo de escribir la misma funcin pero con ajuste de patrones (Pattern Matching).
fact
:: Integer -> Integer
fact
0
= 1
fact (n+1) = (n+1) * fact n

f <pat1> <pat2> . . . <patn> = <expresion>


Donde cada una de las expresiones < pat1 >< pat2 > ... < patn > representa un argumento2 de la
funcin y es denominado un patrn. El nmero n de argumentos se denomina aridad. Si f fuese definida
por ms de una ecuacin, cada una debe tener la misma aridad.
Si f fuese un operador sera:

Observar que se us 0 y n+1 para que los patrones sean disjuntos. Al a ser los patrones disjuntos, el
orden en que aparecen las ecuaciones no importa; en caso contrario, s es importante el orden.
Leer seccin 1.5.1 del libro.

<pat1> f <pat2> = <expresion>


Por ejemplo,
minimo
:: (Integer, Integer) -> Integer
minimo (x,y) = if x <= y then x else y
La condicin x <= y se evala a un valor de tipo Bool, es decir, True o False.
2

No es del todo cierto que una funcin tome n argumentos, como se ver en la seccin Currificacin.

2.4.7.

Definiciones locales

Considrese la siguiente funcin que calcula el nmero de races diferentes de una ecuacin cuadrtica de la forma a x2 + b x + c = 0
numeroDeRaices :: Int -> Int -> Int -> Int
numeroDeRaices a b c

10

2.5. S ECCIONES

2. S INTAXIS

DE

H ASKELL

11

2.5. Secciones

| discr > 0
= 2
| discr == 0
= 1
| discr < 0
= 0
where discr = b*b - 4*a*c

Se puede encerrar tambin un argumento junto con el operador.


(x ) y = x y
( y) x = x y

Las definiciones locales pueden tambin ser introducidas por let de la forma:

Una excepcin: (x) se interpreta como la aplicacin del operador unario de negacin.
Leer seccin 1.4.4 del libro.

let <decls> in <expr>


Leer seccin 1.5.2 del libro.
2.4.8.

2.6. Tabla de precedencia/asociatividad de operadores

Expresiones case

Una expresin case puede ser utilizada para evaluar una expresin y, dependiendo del resultado,
devolver uno de los posibles valores.
paridad :: Int -> String
paridad x = case (x mod 2) of
0 -> "par"
1 -> "impar"
2.4.9.

Aplicacin de Funciones

Notar que en la aplicacin de una funcin, los argumentos no necesitan ser encerrados entre parntesis
(cmo usualmente se hace en matemticas). Supngase la siguientes

9
9
8
7
7
6
5
5
4
4
3
2

!!
.
^
*
/,
div,
rem,
+,
\\
++,
:
==,
/=,
<,
<=,
elem,
notElem
&&
||

mod

>=,

>

Observaciones
La aplicacin de funciones tiene la mayor precedencia.

promedio :: Float -> Float -> Float


promedio a b = (a+b)/2

ABC

Por ejemplo, si queremos calcular el promedio entre 5 y 47, podemos hacer en hugs (ver seccin 3):
Hugs> promedio 5 47
26.0

significa

A (B C)

Leer seccin 1.4.5 y 1.4.6 del libro.

2.7. Disposicin del cdigo

Los parntesis van a ser necesarios cuando queramos romper el orden de precedencia estndar de los
operadores. Como la aplicacin de funcin tiene precedencia ms alta que todos los dems operadores,
si queremos calcular el promedio ente 6 y 9+9, tenemos que hacer
Hugs> promedio 6 (9+9)
12.0

Cmo es posible evitar la utilizacin de separadores que marquen el final de una ecuacin, una
declaracin, etc. Por ejemplo, dada la siguiente expresin:
ejemplo x y z = a + b
where a = f x y
b = g z
Cmo sabe el sistema Haskell que no debe analizarla como:

Pues,
promedio 6 9 + 9

infixl
infixr
infixr
infixl
infix
infixl
infix
infixr
infix
infix
infixr
infixr

equivale a

(promedio 6 9) + 9

ejemplo x y z
= a + b
where a
= f x
y b = g z

12

2.7. D ISPOSICIN

DEL CDIGO

La respuesta es que el Haskell utiliza una sintaxis bidimensional denominada espaciado (layout) que
se basa esencialmente en que las declaraciones estn alineadas por columnas. En el ejemplo anterior,
obsrvese que a y b comenzaban en la misma columna. Las reglas del espaciado son bastante intuitivas
y podran resumirse en:
1. El siguiente carcter de cualquiera de las palabras clave where, let u of es el que determina la
columna de comienzo de declaraciones en las expresiones where, let o case correspondientes. Por tanto podemos comenzar las declaraciones en la misma lnea que la palabra clave, en la
siguiente o siguientes.
2. Es necesario asegurarse que la columna de comienzo dentro de una declaracin est ms a la derecha que la columna de comienzo de la siguiente clusula. En caso contrario, habra ambigedad,
ya que el final de una declaracin ocurre cuando se encuentra algo a la izquierda de la columna de
comienzo.
El espaciado es una forma sencilla de agrupamiento que puede resultar bastante til. Por ejemplo, la
declaracin anterior sera equivalente a:
ejemplo x y z = a + b
where { a = f x y ;
b = g z }

3. C OSAS

SOBRE EL

H UGS

13

3. Cosas sobre el Hugs


Existen varias implementaciones de Haskell; nosotros usaremos Hugs, ya que es libre, est disponibles para distintas plataformas (MS-Windows, Mac OS X, Unix), presenta una interfaz de usuario flexible
y es bastante eficiente.

3.1. Prelude.hs
El prelude es un fichero de nombre Prelude.hs que es cargado automticamente al arrancar Hugs
y contiene la definicin de un conjunto de funciones que podemos usar cuando las necesitemos. Algunos
ejemplos: div, mod, sqrt, id, fst, snd.

3.2. Iniciando Hugs


Al iniciar una sesin en Hugs, nos aparecer una ventana como sta:
__
__
||
||
||___||
||---||
||
||
||
||

__ __ ____
___
|| || || || ||__
||__|| ||__|| __||
___||
Version: May 2006

_________________________________________
Hugs 98: Based on the Haskell 98 standard
Copyright (c) 1994-2005
World Wide Web: http://haskell.org/hugs
Report bugs to: hugs-bugs@haskell.org
_________________________________________

Haskell 98 mode: Restart with command line option -98 to enable extensions
Type :? for help
Hugs>
Hugs evaluar cualquier expresin, sintcticamente correcta, que se ingrese en el prompt
Hugs> <expresion>
<resultado>
Por ejemplo, si ingresemos (7 + 4) 3, la evaluar y nos devolver 33
Hugs> (7+4)*3
33
Si ingresamos sqrt 2, nos devolver una aproximacin de
Hugs> sqrt 2
1.4142135623731

14

3.4. U N

3.3.

PROGRAMA EN

H ASKELL

Comandos de Hugs

3. C OSAS

SOBRE EL

H UGS

15

A una lista de definiciones se la denomina script. Los pasos a seguir para resolver un problema seran
los siguientes:

Si uno escribe :? y presiona ENTER:


LIST OF COMMANDS: Any command may be abbreviated to :c where
c is the first character in the full name.
:load <filenames>
:load
:also <filenames>
:reload
:project <filename>
:edit <filename>
:edit
:module <module>
<expr>
:type <expr>
:?
:set <options>
:set
:names [pat]
:info <names>
:browse <modules>
:find <name>
:!command
:cd dir
:gc
:version
:quit

load modules from specified files


clear all files except prelude
read additional modules
repeat last load command
use project file
edit file
edit last module
set module for evaluating expressions
evaluate expression
print type of expression
display this list of commands
set command line options
help on command line options
list names currently in scope
describe named objects
browse names defined in <modules>
edit module containing definition of name
shell escape
change directory
force garbage collection
print Hugs version
exit Hugs interpreter

La primer lnea dice que se puede usar como abreviatura slo la primera letra de cada comando. Observar
estos comandos equivalentes:
Hugs>
id ::
Hugs>
id ::
Hugs>

:type id
a -> a
:t id
a -> a

El comando :t imprime el tipo de una expresin.

3.4.

Un programa en Haskell

Por ahora hemos evaluado expresiones en el prompt de Hugs y escrito algunas definiciones. Pero,
dnde guardamos esas definiciones? cmo hacemos para usarlas? En esta seccin responderemos
todas estas cuestiones.

1. Escribimos un script con la definicin de todas las funciones que necesitemos para resolver el problema. Para ello podemos utilizar cualquier editor de texto, aunque es recomendable usar alguno
que resalte automticamente la sintaxis de Haskell. Guardamos el archivo con una extensin .hs.
2. Cargamos el script en Hugs. Para ello utilizamos el comando :load seguido del nombre del archivo. Ahora en el prompt de Hugs ya podemos evaluar cualquier expresin que haga referencia a
funciones definidas en el script.
Al escribir el script debemos recordar que Haskell distingue entre maysculas y minsculas (se dice
que es Case Sensitive. Por ejemplo, mi_funcion y mi_Funcion resultan identificadores distintos.
Una buena prctica de programacin es documentar siempre el cdigo fuente. Un comentario en un
script es informacin de valor para el lector humano, ms que para el computador (no interviene para
nada al momento de evaluar una expresin). El smbolo -- inicia un comentario, que ocupa la parte
de la linea hacia la derecha del smbolo.

16

4.2. N MEROS

4.

ENTEROS

Tipos de Haskell

DE

H ASKELL

Para qu sirven los tipos?

Existen dos tipos bsicos para representar enteros: Int e Integer. Ambos incluyen los enteros
negativos, el cero y los enteros positivos. La nica diferencia es que Int representa enteros de rango
acotado, mientras que Integer representa enteros de rango arbitrario.
Esto significa que operar con valores de tipo Int puede provocar un desbordamiento, y el resultado
puede no ser el correcto. En cambio, la aritmtica Integer no presenta este inconveniente. Notar que
este beneficio se gana a costo de algo de prdida de performance: la aritmtica Integer es ms lenta
que la aritmtica Int.

Deteccin de errores comunes


Documentacin
Especificacin rudimentaria

En el prelude se incluye un amplio conjunto de operadores y funciones que manipulan enteros:

Oportunidad de optimizacin en compilacin


Importante: es una buena prctica en programacin empezar dando el tipo del programa que se quiere
escribir.
Leer el captulo 2 del libro

(+)
(*)
(-)
(^)
negate
div
rem/mod

Booleanos

Se representan por el tipo Bool y contienen dos valores: False y True. El tipo de datos Bool se
puede definir con una declaracin de tipos de datos:
data Bool

False | True

El prelude incluye varias funciones para manipular valores booleanos:


Sintaxis de Haskell

Sintaxis estndar en lgica

x && y
x || y
not x
x == y
x /= y

xy
xy
x
xy
x 6 y o x xor y

Haskell tambien incluye una construccin que permite seleccionar entre dos alternativas dependiendo
de un valor booleano.
if condicion then expresion1 else expresion2
funciona de la siguiente manera: se evala condicion; si reduce a True (i.e. la condicin es verdadera)
se evalua expresion1 y se devuelve su valor, y si reduce a False (i.e. la condicin es falsa), se evalua y
devuelve el valor de expresion2.
Obsrvese que una expresin de ese tipo slo es aceptable si condicion es de tipo Bool y si
expresion1 y expresion2 son del mismo tipo.
Leer seccin 2.1 del libro.

17

4.2. Nmeros enteros

Se introduce algunos tipos de datos bsicos (Booleanos, Char, Int) y tipos de datos compuestos (tuplas, listas, funciones).

4.1.

4. T IPOS

odd
even
abs
signum

suma.
multiplicacin.
substraccin.
potenciacin.
menos unario (la expresin "-x" se toma como "negate x")
divisin entera
resto de la divisin entera. Siguiendo la ley:
(x div y)*y + (x rem y) == x
mdulo, como rem slo que el resultado tiene el mismo
signo que el divisor.
devuelve True si el argumento es impar
devuelve True si el argumento es par.
valor absoluto
devuelve -1, 0 o 1 si el argumento es negativo, cero
positivo, respectivamente.

Ejemplos
3^4 == 81, 7 div 3 == 2, even 23 == False
7 rem 3 == 1, -7 rem 3 == -1, 7 rem -3 == 1

4.3. Nmero en punto flotantes


En ciencias de la computacin, a los nmeros con parte fraccionaria, se los denomina nmeros en
punto flotante. En Haskell, stos estan provistos por los tipos bsicos Float y Double.
Tener en cuenta que estos valores son aproximaciones que se representan con un nmero fijo de
dgitos, y que bajo ciertas circunstancias esto puede provocar errores de redondeo.
Los nmeros pueden describirse con la notacin decimal estndar, o utilizando notacin cientfica;
por ejemplo, 1.0e3 equivale a 1000.0, mientras que 5.0e-2 equivale a 0.05.
Otro uso corriente de los nmeros en punto flotante es para representar enteros que son demasiado
grandes en valor absoluto para declararse como Int, pero que tienen pocos dgitos significativos, por
ejemplo 56.23e12.

18

4.4. C ARACTERES

4. T IPOS

La diferencia entre Float y Double reside en que los primeros representan nmeros en punto
flotante de precisin simple, mientras que los segundos, nmeros en punto flotante de precisin doble.
El prelude incluye tambin mltiples funciones de manipulacin de flotantes:
(+), (-), (*), (/)
(^)
(**)
sin, cos, tan
asin, acos, atan
ceiling
floor
truncate

round
fromIntegral
log
sqrt

4.4.

Suma, resta, multiplicacin y


divisin fraccionaria.
Exponenciacin con exponente entero.
Exponenciacin con exponente fraccionario.
Seno, coseno y tangente.
Arcoseno, arcocoseno y arcotangente.
Convierte un nmero fraccionario en un
entero redondeando hacia el infinito.
Convierte un nmero fraccionario en un
entero redondeando hacia el menos infinito.
Convierte un nmero fraccionario en un entero
redondeando hacia el cero (trunca la
parte decimal).
Convierte un nmero fraccionario en un entero
redondeando hacia el entero ms cercano.
Convierte un entero en un nmero en
punto flotante.
Logaritmo en base e.
Raz cuadrada (positiva).

Caracteres

Representados por el tipo Char, los elementos de este tipo representan caracteres individuales como
los que se pueden introducir por teclado. Los valores de tipo carcter se escriben encerrando el valor
entre comillas simples, por ejemplo

mayusc :: Char -> Char


mayusc c = chr (ord c - ord a + ord A)
Leer seccin 2.2 del libro.

4.5. Tipos de Funciones


Si a y b son dos tipos, entonces a b es el tipo de una funcin que toma como argumento un
elemento de tipo a y devuelve un valor de tipo b. Las funciones en Haskell son objetos de primera
clase. Pueden ser argumentos o resultados de otras funciones o ser componentes de estructuras de datos.
Esto permite simular mediante funciones de un nico argumento, funciones con mltiples argumentos.
Considrese, por ejemplo, la funcin de suma (+). En matemticas se toma la suma como una funcin
que toma una pareja de enteros y devuelve un entero. Sin embargo, en Haskell, la funcin suma tiene el
tipo:
(+) :: Int -> (Int -> Int)
(+) es una funcin de un argumento de tipo Int que devuelve una funcin de tipo Int Int. De
hecho (+) 5 denota una funcin que toma un entero y devuelve dicho entero ms 5. Este proceso se
denomina currificacin y permite reducir el nmero de parntesis necesarios para escribir expresiones.
De hecho, no es necesario escribir f(x) para denotar la aplicacin de la funcin f al argumento x, sino
simplemente f x. Ver ms sobre currificacin en la seccin 5.2.
Leer sobre currificacin en seccin 1.4.2 del libro.
Cul es la operacin bsica de una funcin?
La Aplicacin a un elemento de su partida. La Aplicacin es la operacin con mayor precedencia.
Qu expresiones denotan funciones?

Algunos caracteres especiales deben ser introducidos utilizando un cdigo de escape; cada uno de
stos comienza con el carcter de barra invertida (\) , seguido de uno o ms caracteres que seleccionan
el carcter requerido. Algunos de los ms comunes cdigos de escape son:

En contraste con algunos lenguajes comunes (como el C, por ejemplo), los valores de tipo Char son
completamente distintos de los enteros. Sin embargo, el prelude proporciona dos funciones primitivas,
ord y chr, que permiten realizar la conversin.

19

Por ejemplo, la siguiente funcin convierte maysculas en minsculas.

Notar que 0 y 0 son dos valores distintos. El primero es de tipo caracter y el segundo de tipo
entero.

barra invertida
comilla simple
comilla doble
salto de lnea

H ASKELL

ord :: Char -> Int


chr :: Int -> Char

a, 0, ., y Z

\\
\
\"
\n

DE

Nombres definidos como funciones: Ej.: cuadrado

Funciones Annimas3 (lambda abstracciones). Ej.: (\ x x + x)


Resultado de usar otras funciones. Ej.: cuadrado . cuadrado

4.6. Listas
Si a es un tipo cualquiera, entonces [a] representa el tipo de listas cuyos elementos son valores de
tipo a. Por ejemplo,
3

Ver ms sobre Funciones Annimas en 5.1

20

4.7. C ADENAS (S TRING )

4. T IPOS

xs :: [Int]
xs = [1, 8, 2, 4]

DE

H ASKELL

21

Hugs> concat ["Esto"," ","es"," ","una"," ", "cadena"]


"Esto es una cadena"

El prelude incluye un amplio conjunto de funciones de manejo de listas, por ejemplo:


length xs
xs ++ ys
concat xss
map f xs

devuelve el nmero de elementos de xs


devuelve la lista resultante de concatenar
xs e ys
devuelve la lista resultante de concatenar
las listas de xss
devuelve la lista de valores obtenidos al aplicar
la funcin f a cada uno de los elementos de la
lista xs.

Convenio: para representar una lista se usa el convenio xs, para listas de listas se usa xss, y as sucesivamente.

Hugs> map ord "Hola"


[104, 111, 108, 97]
Hugs>
La diferencia entre a y a es que lo primero es un carcter, mientras que lo segundo es una lista de
caracteres que contiene un nico elemento.
Leer seccin 2.7 del libro.

4.8. Enumeraciones
Un modo de definir un nuevo tipo de datos es enumerar explcitamente sus valores. Por ejemplo,
data Dia = Dom | Lun | Mar | Mie | Jue | Vie | Sab

Luego, volveremos con las Listas.

4.7.

Cadenas (String)

Una cadena es tratada como una lista de caracteres y el tipo String se toma como una abreviacin
de [Char]. El tipo String es un renombramiento:
type String = [Char]

Los nombres de las constructoras se distinguen de otras clases de nombres hacindolos comenzar por
una letra mayscula. El nombre de un tipo declarado, tambin comienza por una letra mayscula.
El tipo Dia define un conjunto de siete valores distintos. Cada uno de estos valores se dice qie es un
contructores del tipo Dia.
Por defecto, esta definicin no me permite operar con valores de tipo Dia en la manera que esperaria:
no puedo comparar dos valores por igualdad, no puedo imprimir sus valores en pantalla, etc.
Para poder hacer esto, debo agregarle a la defincin una opcin ms:

Las cadenas pueden ser escritas como secuencias de caracteres encerradas entre comillas dobles. Todos
los cdigos de escape utilizados para los caracteres, pueden utilizarse para las cadenas.
Hugs> "hola"
"hola"

data Dia = Dom | Lun | Mar | Mie | Jue | Vie | Sab


deriving(Eq, Ord, Enum, Show)
que hace que se genere automticamente las declaraciones de las instancias de las clases de tipos nombradas.
Si a es el tipo siendo definido,

Hugs> [h,o,l,a]
"hola"

Eq: permite usar los operadores == y /= con valores de tipo a,

Hugs>

Ord: permite usar los operadores <, <=, > y >= con valores de tipo a. La relacin < est dada
por el orden en que se enumeran los constructores en la definicin del tipo. As, Lun < Vie y
Dom < Sab,

Puesto que las cadenas son representadas como listas de caracteres, todas las funciones para listas
pueden ser utilizadas tambin con cadenas:

Enum: define las funciones fromEnum :: a -> Int y toEnum :: Int -> a. La funcin fromEnum asocia un natural a cada uno de los valores de a, de acuerdo al orden en la
declaracin y comenzando con 0. toEnum es la inversa a izquierda de fromEnum. Por ejemplo
fromEnum Dom reduce a 0, fromEnum Mie reduce a 3 y toEnum 2 == Mar4 reduce a
True.

Hugs> length "Hola"


4
Hugs> "Hola, " ++ "amigo"
"Hola, amigo"

No se puede inferir el tipo de toEnum 2.

22

4.10. P OLIMORFISMO

Show: permite imprimir los valores del tipo a en pantalla.

4. T IPOS

DE

H ASKELL

23

Entonces, la identidad es una funcin polimrfica. El tipo de su argumento puede ser instanciado. Por
ejemplo,

Leer seccin 2.3 del libro.

4.9.

(id 3)
:: Int
(id True) :: Bool

Tuplas

Un modo de combinar tipos para crear tipos nuevos es construir pares. El tipo (A,B) corresponde a
la operacin de producto cartesiano de la teora de conjuntos.
Contamos con los destructores fst y snd que devuelve la primer y segunda componente de un par
respectivamente; por ejemplo fst (2,b) reduce a 2 y snd (2,b) reduce a b.
Ms general, si T1 , T2 , ..., Tn son tipos y n 2, entonces hay un tipo de n-tuplas escrito (T1 , T2 , ..., Tn )
cuyos elementos pueden ser escritos como (x1 , x2 , ..., xn ) donde cada x1 , x2 , ..., xn tiene tipos T1 , T2 , ..., Tn
respectivamente.
Ejemplo
(1, [2], 3)
:: (Int, [Int], Int)
(a, False) :: (Char, Bool)
((1,2),(3,4)) :: ((Int, Int), (Int, Int))
Obsrvese que, a diferencia de las listas, los elementos de una tupla pueden tener tipos diferentes. Sin
embargo, el tamao de una tupla es fijo.
Por completitud, Haskell tambin proporciona una tupla vaca. Por definicin, la expresin (), leda
unit, tiene tipo (). El tipo () tiene dos elementos, y (). Un uso posible de () es convertir las constantes
en funciones; por ejemplo,
pifun
pifun

:: () -> Float
= 3.14159

Al elevar las constantes al nivel de las funciones, se puede ir ms all en el estilo de programacin no
aplicativo. Por ejemplo, se podra escribir
cuadrado . cuadrado . pifun

en lugar de

(cuadrado . cuadrado) pi

Leer seccin 2.4 del libro.

4.10. Polimorfismo
Algunas funciones y operadores trabajan con muchos tipos. Por ejemplo,
id :: a -> a
id x = x
Se lee id es una funcin que dado un elemento de algn tipo a, retorna un elemento de ese mismo tipo.
Aqu a denota variables de tipo. Un tipo que contenga variables de tipo se denomina tipo polimrfico.

Leer seccin 1.6.1 del libro.

y aqu
y aqu

id :: Int -> Int


id :: Bool -> Bool

24

5.2. C URRIFICACIN

5.

Ms sobre funciones

25

SOBRE FUNCIONES

Otra definicin, esencialmente equivalente, de la misma funcin es:

Aqu se explica que es currificacin, y se da diferentes formas de construir funciones.

5.1.

5. M S

Funciones annimas (lambda abstracciones)

sumac :: Integer -> Integer -> Integer


sumac x y = x + y
Veamos antes algo sobre funciones annimas.

Una expresin que denota una funcin son las lambda abstracciones:

(\y -> y + 1)

x . x+x

< def. de lambda expresiones >


(y + 1) [ y := 8 ]

var . expresion

< Sustitucin >


8 + 1

var: es el binder. La variable de cuantificacin o ligador.

< Aritmtica >


9

expresion: es el scope. El alcance de la variable de cuantificacin.


Esto es la funcin sucesor, definida comnmente como:
En Haskell se escriben as
\ x -> x + x

succ :: Integer -> Integer


succ y = y + 1
O sea,

El significado es el siguiente:
(\ x E) x0 E [x := x0 ]
Por ejemplo,

succ = \y -> y + 1
Y la expresin anterior queda

(\x -> x + x)

(\y -> y + 1)
< Por regla anterior >

(x + x) [ x := 2 ]
=

< def. de succ >


succ 8

< Sustitucin >

2 + 2

< def. de succ >


9

< Aritmtica >


4

Veamos dos formas equivalentes de definir una misma funcin:


doble x
doble

5.2.

=
=

x+x
\xx+x

Currificacin

Un artificio til para reducir el nmero de parntesis de una expresin consiste en reemplazar un argumento estructurado por una secuencia de argumentos ms simples. Para ilustrar esta idea, consideremos
la funcin suma.
suma :: (Integer,Integer) -> Integer
suma (x,y) = x + y

Si quisiramos generalizar an ms la funcin anterior y en vez de sumar 1 se suma un x genrico. Para


el ejemplo siguiente, la funcin (annima) recibe dos argumentos (uno despus del otro); en este caso,
12 y luego 89, y se intentar sumarlos.

=
=
=
=
=

(\x -> (\y -> x + y))


<
((\y -> x + y) 89) [x
<
(\y -> 12 + y) 89
<
(12 + y) [ y := 89 ]
<
12 + 89
<
101

12 89
def. de lambda expresiones >
:= 12]
Sustitucin >
def. de lambda expresiones >
Sustitucin >
Aritmtica >

26

5.2. C URRIFICACIN

Observe aqu que la funcin annima se comporta como lo hara sumac. Veamos qu es lo que sucede:
sumac
sumac x
sumac x y

=
=
=

\ x (\ y x + y)
\y x+y
x+y

Para que la currificacin funcione de un modo consistente, necesitamos que la operacin de aplicacin
funcional asocie a la izquierda en las expresiones. As,
sumac x y
cuadrado cuadrado x

significa
significa

(suma x) y
(cuadrado cuadrado) x

Observar que la ltima es incorrecta. Tambin observar que el operador asocia a la derecha. Esto es:
ABC

significa

A (B C)

Ver en la tabla de asociatividad en la seccin 2.6.


La currificacin conlleva dos ventajas. En primer lugar, puede ayudar a reducir el nmero de parntesis que han de escribirse en las expresiones. En segundo lugar, las funciones currificadas pueden ser
aplicadas a un solo argumento, dando como resultado otra funcin que puede ser til por s misma. Por
ejemplo,

5. M S

27

SOBRE FUNCIONES

La funcin uncurry hace lo opuesto y convierte una funcin currificada en otra que no lo es.
uncurry :: (a -> b -> c) -> (a,b) -> c
uncurry f (x,y) = f x y
Leer seccin 1.4.2 del libro.
5.2.1.

Forma prctica de ver la Currificacin

Para fines prctico, slo es necesario pensar que la funciones toman una secuencia de argumentos y
devuelve un resultado. Por ejemplo,
suma4 :: Int -> Int -> Int -> Int -> Int
suma4 x1 x2 x3 x4 = x1 + x2 + x3 + x4
Aunque nos quedamos con sta idea intuitiva de currificacin, es didctico ver cmo queda poniendo
todos los parntesis.
suma4 :: Int -> (Int -> (Int -> (Int -> Int)))
(((suma4 x1) x2) x3) x4 = x1 + x2 + x3 + x4
Nos quedamos con la primera definicin de suma4.

suma 1 = succ

5.3. Composicin de Funciones


Demostraremos sto, primero recordar
La composicin de dos funciones f y g se define mediante la ecuacin
sumac x
=

< Una de las def. de sumac >


\y -> x + y

La funcin (f . g) aplicada a x se define como el resultado de aplicar primero g a x, y luego aplicar


al resultado f.

Instanciando el x a 1
sumac 1
=

(.) :: (b -> c) -> (a -> b) -> a -> c


(f . g) x = f (g x)

< Def. de sumac >

Recordar la Relacin entre identificadores y operadores (ver 2.4.3). Por dicha relacin, una definicin alternativa sera,

\y -> 1 + y
=

< Conmunt. >


\y -> y + 1

< Def. de succ >


succ

(.) :: (a -> b) -> (c -> a) -> c -> b


(.) f g x = f (g x)
Pero nos quedaremos con la primera.
La composicin funcional es una operacin asociativa.

Si lo deseamos, siempre podemos convertir una funcin no currificada en otra currificada. La funcin
curry toma un funcin no currificada y devuelve un versin currificada de la misma funcin; su definicin
es
curry :: ((a,b) -> c) -> a -> b -> c
curry f x y = f (x,y)

(f . g) . h

f . (g . h)

para todas las funciones f, g y h de tipos apropiados. En consecuencia, no hay necesidad de poner
parntesis al escribir secuencias de composiciones.
Leer seccin 1.4.7 del libro.

28

5.4. F UNCIONES

5.4.

TOTALES Y PARCIALES .

Funciones totales y parciales.

Decimos que una funcin es total, si est definida para todo elemento de su dominio. En otras palabras, f :: A -> B es total si y slo si f x 6= para todo x::A. En caso contrario, decimos que
f es parcial. Ver la definicin de Botton () en la seccin 6.1.

6. E VALUACIN

29

6. Evaluacin
6.1. Reduccin
Definicin: cero o ms contracciones (reemplazo de un redex).

Por ejemplo, si definimos


double :: Integer -> Integer
double x = 2 * x

Redex (reducible expresin): subexpresin que coincide con una instancia del lado izquierdo de un
ecuacin. Un redex ms interno es aquel que no contiene otro redex. Un redex ms externo es aquel que
no est contenido en otro redex. Otra definicin posible, subexpresin que se puede reemplazar por otra.

fact :: Integer -> Integer


fact n = if n==0 then 1 else n * fact(n-1)

Forma normal: expresin que no contiene redexes (o sea, expresin que no se puede reducir). No toda
expresin tiene forma normal. La reduccin pretende obtener la formal normal.

reciproco :: Float -> Float


reciproco x = 1/x

Cul es el valor de infinito? Definido as:


infinito = infinito + 1

double resulta una funcin total, mientras que fact y reciproco resultan parciales. Esto se
debe a que fact aplicado a un entero negativo denota una computacin que no termina, y reciproco
no est definido en cero.
Notar que en programacin funcional tenemos una definicin diferente de dominio de una funcin a
la que tenemos usualmente en matemticas. En matemticas escribimos f : A B para denotar que f
es una funcin definida para todo x en A, mientras que en Haskell, f :: A -> B significa que f est
definida (i.e. no evala a ) para eventualmente alguno de los valores en A.

Visin denotacional:
Botton (): valor terico que representa a un error o a una computacin que no termina.
Visin operacional:
expresin cuyas computaciones no terminan (infinitos).
expresin que no estn definidas (1/0).
Notas
No se puede manejar de manera operacional.
No se puede preguntar si algo es sin obtener . Comparacin con da .
Funcin estricta:

f=

Si la funcin necesita el valor para dar el resultado entonces es estricta


Funcin no estricta:

f=
6

Orden de evaluacin: algoritmo para la eleccin del redex a reducir.


Reduccin ms interna u orden aplicativo: primero los redexes ms internos. Tambin llamada
evaluacin impaciente.
Reduccin ms externa u orden normal: primero los redexes ms externos.
Nota: en ambos casos, si hay ms de un redex al mismo nivel, elige el de ms a la izquierda.

30

6.2. E VALUACIN

PEREZOSA ( O

Lazy)

Propiedad 1. La reduccin ms externa tiene la propiedad importante de que si una expresin tiene
forma normal, entonces sta la encontrar.

6. E VALUACIN

31

6.2. Evaluacin perezosa (o Lazy)


Es una evaluacin en orden normal, con las siguientes caractersticas adicionales:

Cul es el resultado de evaluar en orden aplicativo la siguiente expresin:


fst (2, infinito)

=
=
=
=
.
.
.

fst
fst
fst
fst

(2,
(2,
(2,
(2,

infinito
infinito
infinito
infinito

+
+
+
+

1)
1 + 1)
1 + 1 + 1)
1 + 1 + 1 + 1)

Propiedad 2.

Orden aplicativo
Orden normal

Un argumento no es necesariamente evaluado por completo; slo se evalan aquellas partes que
constituyen efectivamente al cmputo.
Si un argumento se evala, tal evaluacin se realiza slo una vez.
Ventajas

Y cul es el resultado de evaluar la misma expresin en orden normal:


fst (2, infinito)

El argumento de una funcin slo se evala cuando es necesario para el cmputo.

Termina siempre que cualquier otro orden de reduccin termine.


No requiere ms (sino posiblemente menos) pasos que la evaluacin impaciente.

2
TODAS las funciones son estrictas
hay funciones estrictas y no estrictas

Nota: la reduccin ms externa a veces puede necesitar ms pasos que la reduccin ms interna. El
problema surge con cualquier funcin cuya definicin contenga apariciones repetidas de un argumento.
Por ejemplo, el resultado de evaluar en orden aplicativo la siguiente expresin:

< def. de + >


cuadrado 7

< def. de cuadrado >


< def. de * >
49

Y es el resultado de evaluar la misma expresin en orden normal:


cuadrado (3 + 4)
=

< def. de cuadrado >


(3 + 4) * (3 + 4)

< def. de + >


7 * (3 + 4)

< def. de + >


7 * 7

< def. de * >


49

Obsrvese que se necesit un paso ms porque en la definicin de cuadrado aparece repetido su argumento. Esto es:
cuadrado x = x * x

Desventajas

Adoptaremos la evaluacin lazy como nuestro modelo de clculo porque tiene las propiedades deseables anteriormente mencionadas.
Leer seccin 7.1 del libro.

7 * 7
=

Manipulacin de computaciones infinitas.

Es difcil calcular el costo de ejecucin.

cuadrado (3 + 4)
=

Manipulacin de estructura de datos infinitas.

También podría gustarte