import Data.List (delete, nub)
-- Definiciones de sumasSumandosDistintos
-- ======================================
-- 1ª definición sumasSumandosDistintos
sumasSumandosDistintos :: Integer -> [[Integer]]
sumasSumandosDistintos n = aux n [1..n]
where aux 0 _ = [[]]
aux _ [] = []
aux x ys@(y:_)
| x < y = []
| x == y = [[x]]
| otherwise = [z : zs | z <- ys
, zs <- aux (x - z) (dropWhile (<=z) ys)]
-- 2ª definición de sumasSumandosDistintos
sumasSumandosDistintos2 :: Integer ->[[Integer]]
sumasSumandosDistintos2 = aux 0
where aux i z
| z < 0 = []
| z == 0 = [[]]
| z > 0 = concat [map (j:) (aux j (z-j)) | j <- [i+1..z]]
-- Definición de nSumasSumandosDistintos
-- =====================================
nSumasSumandosDistintos :: Integer -> Int
nSumasSumandosDistintos =
length . sumasSumandosDistintos
-- Definiciones de sumasSumandosImpares
-- ====================================
-- 1ª definición de sumasSumandosImpares
sumasSumandosImpares :: Integer -> [[Integer]]
sumasSumandosImpares n = aux n [1,3..n]
where aux n _ | n < 0 = []
aux 0 _ = [[]]
aux _ [] = []
aux x zs@(y:ys) = [y:zs | zs <- aux (x-y) zs] ++ aux x ys
-- 2ª definición de sumasSumandosImpares
sumasSumandosImpares2 :: Integer ->[[Integer]]
sumasSumandosImpares2 = aux 1
where aux i z
| z < 0 = []
| z == 0 = [[]]
| z > 0 = concat [map (j:) (aux j (z-j)) | j <-[i,i+2..z]]
-- Definición de nSumasSumandosImpares
-- ===================================
nSumasSumandosImpares :: Integer -> Int
nSumasSumandosImpares =
length . sumasSumandosImpares
-- Definición conjunta (de josejuan)
-- =================================
-- podemos definir una gran familia de generadores de la siguiente forma
sumas :: Integer ->Integer ->Integer ->Integer ->Integer ->[[Integer]]
sumas u a b k n = s u n where
s i z | z < 0 = []
| z == 0 = [[]]
| z > 0 = concat [map (j:) (s j (z - j)) | j <-[k*i+a,k*i+b..z]]
-- así, si queremos los distintos
sumasSumandosDistintos3 :: Integer ->[[Integer]]
sumasSumandosDistintos3 = sumas 0 1 2 1
-- o queremos los impares repetidos
sumasSumandosImpares3 :: Integer ->[[Integer]]
sumasSumandosImpares3 = sumas 1 0 2 1
-- Igualdad de las sumas
-- =====================
igualdadDeSumas :: Integer -> Bool
igualdadDeSumas n =
and [nSumasSumandosDistintos k == nSumasSumandosImpares k | k <- [1..n]]
-- Comparación de eficiencia
-- =========================
-- λ> length (sumasSumandosDistintos2 70)
-- 29927
-- (0.57 secs, 374,604,848 bytes)
-- λ> length (sumasSumandosDistintos3 70)
-- 29927
-- (0.57 secs, 352,658,200 bytes)
-- λ> length (sumasSumandosImpares 70)
-- 29927
-- (8.87 secs, 5,221,638,688 bytes)
-- λ> length (sumasSumandosImpares2 70)
-- 29927
-- (0.61 secs, 422,132,696 bytes)
-- λ> length (sumasSumandosImpares3 70)
-- 29927
-- (0.56 secs, 412,289,336 bytes)