import Data.List (intersect, nub)
import Data.Numbers.Primes (primes, primeFactors)
-- (parientes x y) se verifica si x e y son parientes. Por ejemplo,
-- parientes 12 40 == True
-- parientes 49 63 == True
-- parientes 12 30 == False
-- parientes 49 25 == False
-- 1ª definición (con gcd)
parientes1 :: Integer -> Integer -> Bool
parientes1 x y =
length [p | p <- takeWhile (<= d) primes, d `mod` p == 0] == 1
where d = gcd x y
-- 2ª definición (con primeFactors)
parientes2 :: Integer -> Integer -> Bool
parientes2 0 0 = False
parientes2 x y =
length (nub (primeFactors x `intersect` primeFactors y)) == 1
-- Comparación de eficiencia
-- ghci> parientes1 (2^25) (2^25)
-- True
-- (34.34 secs, 15974866184 bytes)
-- ghci> parientes2 (2^25) (2^25)
-- True
-- (0.01 secs, 3093024 bytes)
-- Usaremos la 2ª definición
parientes :: Integer -> Integer -> Bool
parientes = parientes2
-- Definiciones de secuenciaParientes
-- ==================================
-- 1ª definición (por recursión)
secuenciaParientes :: [Integer] -> Bool
secuenciaParientes [] = True
secuenciaParientes [x] = True
secuenciaParientes (x1:x2:xs) =
parientes x1 x2 && secuenciaParientes (x2:xs)
-- 2ª definición (por recursión con 2 ecuaciones)
secuenciaParientes2 :: [Integer] -> Bool
secuenciaParientes2 (x1:x2:xs) =
parientes x1 x2 && secuenciaParientes2 (x2:xs)
secuenciaParientes2 _ = True
-- 3ª definición (sin recursión):
secuenciaParientes3 :: [Integer] -> Bool
secuenciaParientes3 xs = all (\(x,y) -> parientes x y) (zip xs (tail xs))
-- 4ª definición
secuenciaParientes4 :: [Integer] -> Bool
secuenciaParientes4 xs = all (uncurry parientes) (zip xs (tail xs))