import Data.Array ((!), listArray)
import Data.Matrix (fromLists, getDiag)
import Data.Vector (toList)
-- 1ª definición (por recursión):
diagonal1 :: [[a]] -> [a]
diagonal1 ((x:_):xss) = x : diagonal1 [tail xs | xs <- xss]
diagonal1 _ = []
-- 2ª definición (por comprensión):
diagonal2 :: [[a]] -> [a]
diagonal2 xss = [xs!!k | (xs,k) <- zip xss [0..n]]
where n = length (head xss) - 1
-- 3ª definición (con Data.Matrix)
diagonal3 :: [[a]] -> [a]
diagonal3 = toList . getDiag . fromLists
-- 4ª definición (con Data.Array)
diagonal4 :: [[a]] -> [a]
diagonal4 xss = [p!(i,i) | i <- [1..k]]
where m = length xss
n = length (head xss)
k = min m n
p = listArray ((1,1),(m,n)) (concat xss)
-- Comparación de eficiencia
-- λ> let n = 3000 in sum (diagonal1 (replicate n [1..n]))
-- 4501500
-- (2.08 secs, 754,089,992 bytes)
-- λ> let n = 3000 in sum (diagonal2 (replicate n [1..n]))
-- 4501500
-- (0.06 secs, 0 bytes)
-- λ> let n = 3000 in sum (diagonal3 (replicate n [1..n]))
-- 4501500
-- (1.22 secs, 1,040,787,360 bytes)
-- λ> let n = 3000 in sum (diagonal4 (replicate n [1..n]))
-- 4501500
-- (0.96 secs, 624,463,632 bytes)