I'm studying graph-like things handling in Haskell using 'tying the knot' technique. I suppose, cyclic lists is just kind of infinite list internal implementation, so in ideal world one should not care about subj. But it can have dramatic effect on computational complexity, consider the example, 1D cellular automata with looped world:
ribbon = let x = 0 : y
y = 1 : x
in x
update_cycle :: Num a => [a] -> [a]
update_cycle lst@(_:xs) = ( f lst : update_cycle xs)
update_cycle [] = error "infinite cycle assumed"
f :: Num a => [a] -> a -- some arbitrary list reduction
f (x:(y:_)) = traceShow "f called" $ x - y
This is a loop with just two cells. Let's make a step:
*Main> take 2 $ update_cycle ribbon
[-1,1]
"f called"
"f called"
Thats good, now two steps:
*Main> take 2 $ (update_cycle . update_cycle) ribbon
[-2,2]
"f called"
"f called"
"f called"
"f called"
"f called"
That's five calls instead of four, and it actually means increase count of calls on each step, so we have quadratic complexity on total step count instead of linear. I've could make cyclics explicit, like this:
newtype UserDefCyclic a = UserDefCyclic { fromTC :: [a] }
udcToList :: UserDefCyclic a -> [a]
udcToList (UserDefCyclic x) = cycle x
update_udc :: Num a => UserDefCyclic a -> UserDefCyclic a
update_udc (UserDefCyclic core) = UserDefCyclic $ take (length core) (update_cycle ( cycle core ))
But it's ugly, while I really interested in more complex structures like graphs. The question: is there a way to have here code both nice and fast? Or is there a hope that compiler will handle code above better in some bright future?