import Data.List (genericReplicate)
-- 1ª solución
-- ===========
productoDiagonal1 :: Num a => [[a]] -> a
productoDiagonal1 xss = product (diagonal1 xss)
-- (diagonal1 xss) es la diagonal de la matriz xss. Por ejemplo,
-- diagonal1 [[3,5,2],[4,7,1],[6,9,0]] == [3,7,0]
-- diagonal1 [[3,5],[4,7],[6,9]] == [3,7]
-- diagonal1 [[3,5,2],[4,7,1]] == [3,7]
diagonal1 :: [[a]] -> [a]
diagonal1 ((x:_):xss) = x : diagonal1 (map tail xss)
diagonal1 _ = []
-- 2ª solución
-- ===========
productoDiagonal2 :: Num a => [[a]] -> a
productoDiagonal2 = product . diagonal1
-- 3ª solución
-- ===========
productoDiagonal3 :: Num a => [[a]] -> a
productoDiagonal3 = product . diagonal3
diagonal3 :: [[a]] -> [a]
diagonal3 xss = [xs !! k | (xs,k) <- zip xss [0..n]]
where n = length (head xss) - 1
-- 4ª solución
-- ===========
productoDiagonal4 :: Num a => [[a]] -> a
productoDiagonal4 [] = 1
productoDiagonal4 [[]] = 1
productoDiagonal4 ((x:_):xss) = x * productoDiagonal4 (map tail xss)
-- 5ª solución
-- ===========
productoDiagonal5 :: Num a => [[a]] -> a
productoDiagonal5 xss = product (zipWith (!!) xss [0..k])
where m = length xss
n = length (head xss)
k = min m n - 1
-- Comparación de eficiencia
-- =========================
ejemplo :: Integer -> [[Integer]]
ejemplo n = genericReplicate n [1..n]
-- La comparación es
-- λ> length (show (productoDiagonal1 (ejemplo 7000)))
-- 23878
-- (1.23 secs, 3,396,129,424 bytes)
-- λ> length (show (productoDiagonal2 (ejemplo 7000)))
-- 23878
-- (0.94 secs, 3,396,127,680 bytes)
-- λ> length (show (productoDiagonal3 (ejemplo 7000)))
-- 23878
-- (0.09 secs, 44,841,864 bytes)
-- λ> length (show (productoDiagonal4 (ejemplo 7000)))
-- 23878
-- (0.96 secs, 3,614,137,840 bytes)
-- λ> length (show (productoDiagonal5 (ejemplo 7000)))
-- 23878
-- (0.07 secs, 44,168,984 bytes)
--
-- λ> length (show (productoDiagonal3 (ejemplo 70000)))
-- 308760
-- (8.26 secs, 5,359,752,408 bytes)
-- λ> length (show (productoDiagonal5 (ejemplo 70000)))
-- 308760
-- (9.34 secs, 5,353,035,656 bytes)