import Data.List (genericLength, nub, sort, subsequences)
-- 1ª definición de funciones
-- ==========================
funciones :: (Ord a, Ord b) => [a] -> [b] -> [[(a,b)]]
funciones xs ys =
conjunto [r | r <- relaciones xs ys
, esFuncion r xs ys]
-- (relaciones xs ys) es el conjunto de las relaciones binarias entre xs
-- e ys. Por ejemplo,
-- λ> relaciones [1,3] [2,4]
-- [[],[(1,2)],[(1,4)],[(1,2),(1,4)],[(3,2)],[(1,2),(3,2)],
-- [(1,4),(3,2)],[(1,2),(1,4),(3,2)],[(3,4)],[(1,2),(3,4)],
-- [(1,4),(3,4)],[(1,2),(1,4),(3,4)],[(3,2),(3,4)],
-- [(1,2),(3,2),(3,4)],[(1,4),(3,2),(3,4)],
-- [(1,2),(1,4),(3,2),(3,4)]]
relaciones :: [a] -> [b] -> [[(a,b)]]
relaciones xs ys =
subsequences (producto xs ys)
-- (producto xs ys) es el producto cartesiano de xs e ys. Por ejemplo,
-- producto [1,3] [2,4] == [(1,2),(1,4),(3,2),(3,4)]
producto :: [a] -> [b] -> [(a,b)]
producto xs ys =
[(x,y) | x <- xs, y <- ys]
-- (esFuncional r) r se verifica si la relación r es funcional. Por
-- ejemplo,
-- esFuncional [(2,4),(1,5),(3,4)] == True
-- esFuncional [(3,4),(1,4),(1,2),(3,4)] == False
esFuncional :: (Ord a, Ord b) => [(a,b)] -> Bool
esFuncional r =
and [esUnitario (imagen r x) | x <- dominio r]
-- (dominio r) es el dominio de la relación r. Por ejemplo,
-- dominio [(5,4),(1,4),(1,2),(3,4)] == [1,3,5]
dominio :: Ord a => [(a,b)] -> [a]
dominio = sort . nub . map fst
-- (imagen r x) es la imagen de x en la relación r. Por ejemplo,
-- imagen [(5,4),(1,4),(1,2),(3,4)] 1 == [2,4]
-- imagen [(5,4),(1,4),(1,2),(3,4)] 2 == []
imagen :: (Ord a, Ord b) => [(a,b)] -> a -> [b]
imagen r x =
conjunto [y | (x1,y) <- r, x1 == x]
-- (conjunto xs) es el conjunto (es decir, lista ordenada de elementos
-- distintos) correspondiente a la lista xs. Por ejemplo,
-- conjunto [7,2,3,2,7,3] == [2,3,7]
conjunto :: Ord a => [a] -> [a]
conjunto = sort . nub
-- (esUnitario xs) se verifica si xs tiene sólo un elemento.
esUnitario :: [a] -> Bool
esUnitario xs =
length xs == 1
-- (esFuncion r xs ys) se verifica si r es una función con dominio xs y
-- codominio ys. Por ejemplo,
-- esFuncion [(2,4),(1,5),(3,4)] [1,2,3] [4,5,7] == True
-- esFuncion [(2,4),(1,5),(3,4)] [1,3] [4,5,7] == False
-- esFuncion [(2,4),(1,5),(3,4)] [1,2,3] [4,7] == False
-- esFuncion [(1,4),(1,5),(3,4)] [1,2,3] [4,5,7] == False
esFuncion :: (Ord a, Ord b) => [(a,b)] -> [a] -> [b] -> Bool
esFuncion r xs ys =
conjunto xs == dominio r
&& rango r `contenido` conjunto ys
&& esFuncional r
-- (rango r) es el rango de la relación r. Por ejemplo,
-- rango [(5,4),(1,4),(1,2),(3,4)] == [2,4]
rango :: Ord b => [(a,b)] -> [b]
rango = sort . nub . map snd
-- (contenido xs ys) se verifica si el conjunto xs está contenido en el
-- ys. Por ejemplo,
-- [1,3] `contenido` [1,2,3,5] == True
-- [1,3] `contenido` [1,2,4,5] == False
contenido :: Ord a => [a] -> [a] -> Bool
contenido xs ys =
all (`elem` ys) xs
-- 2ª definición de funciones
-- ==========================
funciones2 :: (Ord a, Ord b) => [a] -> [b] -> [[(a,b)]]
funciones2 xs ys =
conjunto (aux xs ys)
where aux [] _ = [[]]
aux [x] ys = [[(x,y)] | y <- ys]
aux (x:xs) ys = [((x,y):f) | y <- ys, f <- fs]
where fs = aux xs ys
-- Comparación de eficiencia de funciones
-- ======================================
-- λ> length (funciones [1..4] [1..4])
-- 256
-- (2.69 secs, 754,663,072 bytes)
-- λ> length (funciones2 [1..4] [1..4])
-- 256
-- (0.04 secs, 243,600 bytes)
-- 1ª definición de nFunciones
-- ===========================
nFunciones :: (Ord a, Ord b) => [a] -> [b] -> Integer
nFunciones xs ys =
genericLength (funciones2 xs ys)
-- 2ª definición de nFunciones
-- ===========================
nFunciones2 :: (Ord a, Ord b) => [a] -> [b] -> Integer
nFunciones2 xs ys =
(genericLength ys)^(genericLength xs)
-- Comparación de eficiencia de nFunciones
-- =======================================
-- λ> nFunciones [1..5] [1..5]
-- 3125
-- (1.35 secs, 1,602,872 bytes)
-- λ> nFunciones2 [1..5] [1..5]
-- 3125
-- (0.03 secs, 140,480 bytes) |