Jón Fairbairn <[EMAIL PROTECTED]> writes:
>
> > diagonalise:: [[a]] -> [a]
> > diagonalise l = d [] l
>
>
> > d [] [] = []
> > d acc [] = -- d [] acc would do, but muddles the order;
> > heads acc ++ d (rests acc) []
> > d ls (l1:rest) = heads (ls') ++ d (rests ls') rest
> > where ls' = l1: ls
>
> > heads l = [a | (a: _) <- l]
> > rests l = [as | (_: as) <- l]
>
This differs from the versions given by Mark Jones, Stefan Kahrs and myself
in that it does the diagonals ``upside down''.
However, methodologically it is actually very close to my version,
and even closer to some predecessor of that that I do not have anymore.
In fact, if I introduce into DiagWK3 the corresponding muddling avoidance,
we get:
DiagWK4:
> diag :: [[a]] -> [a]
> diag [] = []
> diag (l:ls) = split id [l] ls
> where
> split :: ([[a]] -> [[a]]) -> [[a]] -> [[a]] -> [a]
> split a [] ls = case ls of
> [] -> split id [] (a [])
> (l:ls) -> split id (a [l]) ls
> split a (l : ls) r = case l of
> [] -> split a ls r
> (x:xs) -> x : split (a . (xs :)) ls r
Then a tiny change turns the diagonals ``upside down'', too:
DiagWK5:
> diag :: [[a]] -> [a]
> diag [] = []
> diag (l:ls) = split id [l] ls
> where
> split :: ([[a]] -> [[a]]) -> [[a]] -> [[a]] -> [a]
> split a [] ls = case ls of
> [] -> split id [] (a [])
> (l:ls) -> split id (l : (a [])) ls -- CHANGED!!
> split a (l : ls) r = case l of
> [] -> split a ls r
> (x:xs) -> x : split (a . (xs :)) ls r
The timing differences between DiagJF and DiagWK5 are probably
mostly due to some combination of
* the double list analysis effort in heads and rests
* and the tradeoff between lists with (++) and functions with (.).
It might be interesting to look into the compiled code in detail.
20000 200000 2000000 5000000
DiagMPJ 0:00.16 0:02.32 0:37.55 1:48.09
DiagMPJ1 0:00.12 0:01.50 0:23.83 1:06.71
DiagMPJ1a 0:00.12 0:01.47 0:23.54 1:06.04
DiagJF 0:00.13 0:01.64 0:21.85 0:57.99
DiagWK3 0:00.12 0:01.34 0:18.82 0:52.31
DiagWK4 0:00.11 0:01.33 0:19.29 0:53.22
DiagWK5 0:00.12 0:01.34 0:18.92 0:52.06
Wolfram