If something is purely functional and doesn't have any fixed point loopholes or other nonsense, you can know that there is no program with circular pointers.
A = [a | A]
Prolog implementations provide destructive operations and mutation, but here above this is done with unification only. Arguably, you could say that unification performs mutation (but only once).This is less strict than pure functional programming, but still feels declarative and makes concurrent programming easy: no piece of code that looked previously at your variable will have its assumptions about it broken.
Lazy evaluation makes it possible to construct circular data structures without mutation.
CL-USER> (subseq '#1=(1 2 3 . #1#) 0 10)
(1 2 3 1 2 3 1 2 3 1)Church-Turing thesis says lambda calculus is turing complete and it is purely functional with no pointers at all.
That being said, reference counting is a really bad fit for functional languages for several other reasons.