I\'m curious as to why Haskell implementations use a GC.
I can\'t think of a case where GC would be necessary in a pure language. Is it just an optimization to reduc
The standard implementation techniques applied to Haskell actually require a GC moreso than most other languages, since they never mutate previous values, instead creating new, modified values based on the previous ones. Since this means the program is constantly allocating and using more memory, a large number of the values will be discarded as time goes on.
This is why GHC programs tend to have such high total allocation figures (from gigabytes to terabytes): they're constantly allocating memory, and it's only thanks to the efficient GC that they reclaim it before running out.
If a language (any language) allows you to allocate objects dynamically, then there are three practical ways to deal with the management of memory:
The language can only allow you to allocate memory on the stack, or at startup. But these restrictions severely limit the kinds of computations that a program can perform. (In practice. In theory, you can emulate dynamic data structures in (say) Fortran by representing them in a big array. It is HORRIBLE ... and not relevant to this discussion.)
The language can provide an explicit free
or dispose
mechanism. But this relies on the programmer to get it right. Any mistake in the storage management can result in a memory leak ... or worse.
The language (or more strictly, the language implementation) can provide an automatic storage manager for the dynamically allocated storage; i.e. some form of garbage collector.
The only other option is to never reclaim dynamically allocated storage. This is not a practical solution, except for small programs performing small computations.
Applying this to Haskell, the language doesn't have the limitation of 1., and there is no manual deallocation operation as per 2. Therefore, in order to be useable for non-trivial things, a Haskell implementation needs to include a garbage collector.
I can't think of a case where GC would be necessary in a pure language.
Presumably you mean a pure functional language.
The answer is that a GC is required under the hood to reclaim the heap objects that the language MUST create. For example.
A pure function needs to create heap objects because in some cases it has to return them. That means that they can't be allocated on the stack.
The fact that there can be cycles (resulting from a let rec
for example) means that a reference counting approach won't work for heap objects.
Then there are function closures ... which also can't be allocated on the stack because they have a lifetime that is (typically) independent of that stack frame in which they were created.
I'm looking for example code that would leak if a GC wasn't present.
Just about any example that involved closures or graph-shaped data structures would leak under those conditions.