While thinking about garbage collection, I realized a simple fact that a garbage collector that is more than reference counting is needed because there are circular references, but there are technically no circular references in the basic (untyped) lambda calculus. All circular references are created using function substitution.
So I wonder whether it's possible to get a reasonable garbage collector, by hypothetically compiling all code to a hypothetical functional programming language that doesn't include extensions to have circular references. But it may need too much work for what a garbage collector is worth.
Meanwhile, in discussions about garbage collection, there are occasionally notes about functional programming languages, implying they may still be relevant.
Are garbage collectors more than reference counting relevant in functional programming languages? When are they relevant?
If they are relevant, is it because a specific feature X, such as memoization, made non-constant time garbage collection absolutely necessary? Or could we say, some other things like cache invalidation has replaced the position of garbage collection, but still had the merit of garbage collection?
If they are not relevant, would the ways simulating mutables always reference something that is actually not needed, to reintroduce garbage collection on the runtime level, or are the difficult situations in garbage collection always correspond to data structures inefficient to implement in pure functional languages, or is there something else, to block such attempts?