allOnes = 1 : allOnes struct node { int x; struct node *next; } allOnesList = { 1, &allOnesList }, *allOnes = &allOnesList;This observation is somewhat relevant to the weird semantics of "lexical" scoping in Python, because the obvious semantics would cause cycle between frame object and function defined in it's scope.
In fact, with more thought, I realized the lazy evaluation is actually orthogonal to forming cyclic data. The "allOnes = 1 : allOnes" line doesn't necessarily form a cycle (depending on the interpreter/compiler, I imagine ghc and any other sensible implementation will form a cycle). Naively, this will just create a thunk which will get repeatedly evaluated, generating a long list of ones.
EDIT: Nevermind, you're right.
I am curious as well though. Maybe you could show an example?
Obviously you can't trigger full GC in your GC code. So you have to write GC code in such a way that it won't trigger GC or, in some cases, very limited mode of GC that you know is safe to perform at that point. It is trickier in languages that implicitly allocates. Traditionally, Lisp programmers are pretty aware of what operation would allocate and good at avoiding them. Plus, an implementation often provide a primitive to turn off GC in certain regions. Another approach is to design a subset of language with guaranteed safety properties and implement the core part of GC with it.