5

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?

Alexey Birukov
  • 932
  • 5
  • 18
  • 5
    I think the most sensible thing would be to switch to a general graph data type right away, e.g. from the [fgl](http://hackage.haskell.org/package/fgl) library. – leftaroundabout Jul 25 '16 at 09:39
  • 1
    I'm not sure if this is exactly what you're asking, but maybe this answer might help: you cannot dynamically tie the knot in Haskell. – pdexter Jul 25 '16 at 12:13
  • @leftaroundabout Yes, it is what I will do probably, but I would prefer better control. Anyway, I want to understand infinite lists in Haskell better. I have a feeling, that things like cyclic lists could be essential for tasks like term rewriting (theorem proving). Those tends to make combinatorial explosion, must be desirable to introduce most economical data structures as soon as possible. – Alexey Birukov Jul 25 '16 at 12:17
  • @pdexter Even using Template Haskell? How fundamental is this restriction? – Alexey Birukov Jul 25 '16 at 12:26
  • 1
    @AlexeyBirukov I'm not sure how Template Haskell would help, since it's a static system. But maybe you have an idea about something I haven't thought of? – pdexter Jul 25 '16 at 12:27
  • @pdexter No, I have no real idea, actually, not used TH myself, only read what other people do. – Alexey Birukov Jul 25 '16 at 12:35
  • I'm not sure what "dynamically tie the knot" means exactly, but I imagine the examples at https://wiki.haskell.org/Tying_the_Knot#Migrated_from_the_old_wiki are instances of it. Anyways it's not the issue here, which has more to do with detecting cyclic structures. – Reid Barton Jul 25 '16 at 14:45
  • 2
    Generally "observing sharing" is a side-effect so to do this consistently will require stepping into `IO`. At this point you can just work with `IORef`s as pointers. – J. Abrahamson Jul 25 '16 at 19:42
  • Reid Barton@ Native cycles cant be detected: http://stackoverflow.com/questions/30272662/would-the-ability-to-detect-cyclic-lists-in-haskell-break-any-properties-of-the – Alexey Birukov Jul 25 '16 at 20:18
  • 2
    Although observable sharing is a side-effect, that doesn't mean it is impossible. It just means you have to get ugly and be careful... http://www.ittc.ku.edu/~andygill/papers/reifyGraph.pdf – luqui Jul 26 '16 at 00:14
  • @luqui, J. Abrahamson Observable sharing looks relevant, went studying. – Alexey Birukov Jul 26 '16 at 10:17

0 Answers0