Tema 3: Tipos y clases
Índice
1. Conceptos básicos sobre tipos
1.1. ¿Qué es un tipo?
- Un tipo es una colección de valores relacionados.
- Un ejemplo de tipos es el de los valores booleanos:
Bool - El tipo
Booltiene dos valoresTrue(verdadero) yFalse(falso). Que
ves un valor del tipoT(quevtiene tipoT) se representa porv :: T
Cálculo de tipo con
:typeλ> :type True True :: Bool λ> :type False False :: Bool
- El tipo
Bool -> Boolestá formado por todas las funciones cuyo argumento y valor son booleanos. Ejemplo de tipo
Bool -> Boolλ> :type not not :: Bool -> Bool
1.2. Inferencia de tipos
Regla de inferencia de tipos:
f :: A -> B, e :: A ------------------- f e :: BTipos de expresiones:
λ> :type not True not True :: Bool λ> :type not False not False :: Bool λ> :type not (not False) not (not False) :: Bool
Error de tipo:
λ> :type not 3 Error: No instance for (Num Bool) λ> :type 1 + False Error: No instance for (Num Bool)
1.3. Ventajas de los tipos
- Los lenguajes en los que la inferencia de tipo precede a la evaluación se denominan de tipos seguros.
- Haskell es un lenguaje de tipos seguros.
- En los lenguajes de tipos seguros no ocurren errores de tipos durante la evaluación.
La inferencia de tipos no elimina todos los errores durante la evaluación. Por ejemplo,
λ> :type 1 `div` 0 1 `div` 0 :: (Integral t) => t λ> 1 `div` 0 *** Exception: divide by zero
2. Tipos básicos
Bool(Valores lógicos):- Sus valores son
TrueyFalse.
- Sus valores son
Char(Caracteres):- Ejemplos:
'a','B','3','+'
- Ejemplos:
String(Cadena de caracteres):- Ejemplos:
"abc","1 + 2 = 3"
- Ejemplos:
Int(Enteros de precisión fija):- Enteros entre \(-2^{31}\) y \(2^{31}-1\).
- Ejemplos:
123,-12
Integer(Enteros de precisión arbitraria):- Ejemplos:
1267650600228229401496703205376.
- Ejemplos:
Float(Reales de precisión arbitraria):- Ejemplos:
1.2,-23.45,45e-7
- Ejemplos:
Double(Reales de precisión doble):- Ejemplos:
1.2,-23.45,45e-7
- Ejemplos:
3. Tipos compuestos
3.1. Tipos listas
- Una lista es una sucesión de elementos del mismo tipo.
[T]es el tipo de las listas de elementos de tipoT.Ejemplos de listas:
[False, True] :: [Bool] ['a','b','d'] :: [Char] ["uno","tres"] :: [String]
- Longitudes:
- La longitud de una lista es el número de elementos.
- La lista de longitud 0,
[], es la lista vacía. - Las listas de longitud 1 se llaman listas unitarias.
El tipo de una lista no informa sobre su longitud:
['a','b'] :: [Char] ['a','b','c'] :: [Char]
El tipo de los elementos de una lista puede ser cualquiera:
[['a','b'],['c']] :: [[Char]]
3.2. Tipos tuplas
- Una tupla es una sucesión de elementos.
(T1, T2, ..., Tn)es el tipo de las n-tuplas cuya componente i-ésima es de tipoTi.Ejemplos de tuplas:
(False,True) :: (Bool,Bool) (False,'a',True) :: (Bool,Char,Bool)
- Aridades:
- La aridad de una tupla es el número de componentes.
- La tupla de aridad 0,
(), es la tupla vacía. - No están permitidas las tuplas de longitud 1.
El tipo de una tupla informa sobre su longitud:
('a','b') :: (Char,Char) ('a','b','c') :: (Char,Char,Char)El tipo de los elementos de una tupla puede ser cualquiera:
(('a','b'),['c','d']) :: ((Char,Char),[Char])
3.3. Tipos de funciones
- Una función es una aplicación de valores de un tipo en valores de otro tipo.
T1 -> T1es el tipo de las funciones que aplica valores del tipoT1en valores del tipoT2.Ejemplos de funciones:
not :: Bool -> Bool isDigit :: Char -> Bool
Ejemplo de función con múltiples argumentos:
suma (x,y)es la suma dexey. Por ejemplo,suma (2,3)es5. Su definición essuma :: (Int,Int) -> Int suma (x,y) = x+y
Ejemplo de función con múltiples valores:
deCeroA nes la lista de los números desde0hastan. Por ejemplo,deCeroA 5es[0,1,2,3,4,5]. Su definición esdeCeroA :: Int -> [Int] deCeroA n = [0..n]
- Notas:
- En las definiciones se ha escrito la signatura de las funciones.
- No es obligatorio escribir la signatura de las funciones.
- Es conveniente escribir las signatura.
4. Parcialización
4.1. Parcialización
- Mecanismo de parcialización (currying en inglés): Las funciones de más de un argumento pueden interpretarse como funciones que toman un argumento y devuelven otra función con un argumento menos.
Ejemplo de parcialización:
suma' :: Int -> (Int -> Int) suma' x y = x+y
suma'toma un enteroxy devuelve la funciónsuma' xque toma un enteroyy devuelve la suma dexey. Por ejemplo,λ> :type suma' 2 suma' 2 :: Int -> Int λ> :type suma' 2 3 suma' 2 3 :: Int
Ejemplo de parcialización con tres argumentos:
mult :: Int -> (Int -> (Int -> Int)) mult x y z = x*y*z
multtoma un enteroxy devuelve la funciónmult xque toma un enteroyy devuelve la funciónmult x yque toma un enterozy devuelvex*y*z. Por ejemplo,λ> :type mult 2 mult 2 :: Int -> (Int -> Int) λ> :type mult 2 3 mult 2 3 :: Int -> Int λ> :type mult 2 3 7 mult 2 3 7 :: Int
4.2. Aplicación parcial
- Las funciones que toman sus argumentos de uno en uno se llaman currificadas (curried en inglés).
- Las funciones
suma'ymultson currificadas. Las funciones currificadas pueden aplicarse parcialmente. Por ejemplo,
λ> (suma' 2) 3 5
Pueden definirse funciones usando aplicaciones parciales. Por ejemplo,
suc :: Int -> Int suc = suma' 1
suc xes el sucesor dex. Por ejemplo,suc 2es3.
4.3. Convenios para reducir paréntesis
- Convenio 1: Las flechas en los tipos se asocia por la derecha. Por ejemplo,
Int -> Int -> Int -> Intrepresenta aInt -> (Int -> (Int -> Int)) - Convenio 2: Las aplicaciones de funciones se asocia por la izquierda. Por
ejemplo,
mult x y zrepresenta a((mult x) y) z - Nota: Todas las funciones con múltiples argumentos se definen en forma currificada, salvo que explícitamente se diga que los argumentos tienen que ser tuplas.
5. Polimorfismo y sobrecarga
5.1. Tipos polimórficos
- Un tipo es polimórfico ("tiene muchas formas") si contiene una variable de tipo.
- Una función es polimórfica si su tipo es polimórfico.
La función
lengthes polimófica. Comprobación:λ> :type length length :: [a] -> Int
- Significa que que para cualquier tipo
a,lengthtoma una lista de elementos de tipoay devuelve un entero. aes una variable de tipos.- Las variables de tipos tienen que empezar por minúscula.
Ejemplos de polimorfismo de
length:length [1, 4, 7, 1] == 4 length ["Lunes", "Martes", "Jueves"] == 3 length [reverse, tail] == 2
5.2. Ejemplos de funciones polimórficas
(fst p)es la primera componente del parp. Por ejemplo,fst (1,'x') == 1 fst (True,"Hoy") == True
Su tipo es
fst :: (a,b) -> a
(head xs) es el primer elemento de =xs. Por ejemplo,head [2,1,4] == 2 head ['b','c'] == 'b'
Su tipo es
head :: [a] -> a
(take n xs) es la lista de los =nprimeros elementos de xs. Por ejemplo,take 3 [3,5,7,9,4] == [3,5,7] take 2 ['l','o','l','a'] == "lo" take 2 "lola" == "lo"
Su tipo es
take :: Int -> [a] -> [a]
(zip xs ys)es la lista de pares de los elementos dexseysen las mismas posiciones. Por ejemplo,zip [3,5] "lo" == [(3,'l'),(5,'o')]
Su tipo es
zip :: [a] -> [b] -> [(a, b)]
ides la función identidad. Por ejemplo,id 3 == 3 id 'x' == 'x'
Su tipo es
id :: a -> a
5.3. Tipos sobrecargados
- Un tipo está sobrecargado si contiene una restricción de clases.
- Una función está sobrecargada si su tipo está sobrecargado.
La función
sumestá sobrecargada. Comprobación:λ> :type sum sum :: (Num a) => [a] -> a
- Significa que que para cualquier tipo numérico
a,sumtoma una lista de elementos de tipoay devuelve un valor de tipoa. Num aes una restricción de clases.- Las restricciones de clases son expresiones de la forma
C a, dondeCes el nombre de una clase yaes una variable de tipo. Ejemplos:
sum [2, 3, 5] == 10 sum [2.1, 3.23, 5.345] == 10.675
5.4. Ejemplos de tipos sobrecargados
Ejemplos de funciones sobrecargadas:
(-) :: (Num a) => a -> a -> a (*) :: (Num a) => a -> a -> a negate :: (Num a) => a -> a abs :: (Num a) => a -> a signum :: (Num a) => a -> a
Ejemplos de números sobrecargados:
5 :: (Num t) => t 5.2 :: (Fractional t) => t
6. Clases básicas
- Una clase es una colección de tipos junto con ciertas operaciones sobrecargadas llamadas métodos.
Clases básicas:
Clase Descripción Eqtipos comparables por igualdad Ordtipos ordenados Showtipos mostrables Readtipos legibles Numtipos numéricos Integraltipos enteros Fractionaltipos fraccionarios
6.1. La clase Eq (tipos comparables por igualdad)
Eqcontiene los tipos cuyos valores con comparables por igualdad.Métodos:
(==) :: a -> a -> Bool (/=) :: a -> a -> Bool
- Instancias:
Bool,Char,String,Int,Integer,FloatyDouble.- tipos compuestos: listas y tuplas.
Ejemplos:
False == True == False False /= True == True 'a' == 'b' == False "aei" == "aei" == True [2,3] == [2,3,2] == False ('a',5) == ('a',5) == True
6.2. La clase Ord (tipos ordenados)
Ordes la subclase deEqde tipos cuyos valores están ordenados.Métodos:
(<), (<=), (>), (>=) :: a -> a -> Bool min, max :: a -> a -> a
- Instancias:
Bool,Char,String,Int,Integer,FloatyDouble.- tipos compuestos: listas y tuplas.
Ejemplos:
False < True == True min 'a' 'b' == 'a' "elegante" < "elefante" == False [1,2,3] < [1,2] == False ('a',2) < ('a',1) == False ('a',2) < ('b',1) == True
6.3. La clase Show (tipos mostrables)
Showcontiene los tipos cuyos valores se pueden convertir en cadenas de caracteres.Método:
show :: a -> String
- Instancias:
Bool,Char,String,Int,Integer,FloatyDouble.- tipos compuestos: listas y tuplas.
Ejemplos:
show False == "False" show 'a' == "'a'" show 123 == "123" show [1,2,3] == "[1,2,3]" show ('a',True) == "('a',True)"
6.4. La clase Read (tipos legibles)
Readcontiene los tipos cuyos valores se pueden obtener a partir de cadenas de caracteres.Método:
read :: String -> a
- Instancias:
Bool,Char,String,Int,Integer,FloatyDouble.- tipos compuestos: listas y tuplas.
Ejemplos:
read "False" :: Bool == False read "'a'" :: Char == 'a' read "123" :: Int == 123 read "[1,2,3]" :: [Int] == [1,2,3] read "('a',True)" :: (Char,Bool) == ('a',True)
6.5. La clase Num (tipos numéricos)
Numes la subclase deEqyShowde tipos cuyos valores son númerosMétodos:
(+), (*), (-) :: a -> a -> a negate, abs, signum :: a -> a
- Instancias:
Int,Integer,FloatyDouble. Ejemplos:
2+3 == 5 2.3+4.2 == 6.5 negate 2.7 == -2.7 abs (-5) == 5 signum (-5) == -1
6.6. La clase Integral (tipos enteros)
Integrales la subclase deNumcuyo tipos tienen valores enteros.Métodos:
div :: a -> a -> a mod :: a -> a -> a
- Instancias:
InteInteger. Ejemplos:
11 =div= 4 == 2 11 =mod= 4 == 3
6.7. La clase Fractional (tipos fraccionarios)
Fractionales la subclase deNumcuyo tipos tienen valores no son enteros.Métodos:
(/) :: a -> a -> a recip :: a -> a
- Instancias:
FloatyDouble. Ejemplos:
7.0 / 2.0 == 3.5 recip 0.2 == 5.0
7. Material complementario
El código del tema se encuentra en este enlace.
Este tema también se encuentra en los siguientes formatos:
- Como transparencias en PDF.
- Como libro interactivo en IHaskell sobre Jupyter.
- Como vídeo de clase.
8. Bibliografía
- R. Bird. Introducción a la programación funcional con Haskell. Prentice
Hall, 2000.
- Cap. 2: Tipos de datos simples.
- A. Gibiansky Typeclasses: Polymorphism in Haskell.
- G. Hutton. Programming in Haskell. Cambridge University Press, 2007.
- Cap. 3: Types and classes.
- B. O'Sullivan, D. Stewart y J. Goerzen. Real World Haskell. O'Reilly, 2008.
- Cap. 2: Types and Functions.
- B.C. Ruiz, F. Gutiérrez, P. Guerrero y J.E. Gallardo. Razonando con
Haskell. Thompson, 2004.
- Cap. 2: Introducción a Haskell.
- Cap. 5: El sistema de clases de Haskell.
- S. Thompson. Haskell: The Craft of Functional Programming, Second
Edition. Addison-Wesley, 1999.
- Cap. 3: Basic types and definitions.