In Rust, how can I get an infinitely nested value, such as the limit point of Peano numbers, or a list with infinitely many values?
In Haskell, such things are no big deal:
data Peano = Zero | Succ Peano
omega :: Peano
omega = fix Succ
But can such thing be done in Rust? I tried this:
enum Peano<'a> {
Zero,
Succ(&'a Peano<'a>)
}
fn main() {
let omega = Peano::Succ(&omega);
}
And I cannot use omega during its initialization.
I also tried this:
enum Peano {
Zero,
Succ(fn () -> Peano)
}
fn main() {
let omega = Peano::Succ(|| omega);
}
And the same problem persists.
Rust does not have built-in garbage collection, so by default you cannot naively create self-referential values except for static/leaked ones. Here's a static infinite structure (which is constructed at compile time, so the compiler can see the dependencies and know it's possible to assemble “timelessly”):
Here's how to use a function to build a structure that is generated as you walk it — this is allowed because function items also exist statically/timelessly, so you can use a function inside itself (just like in a recursive function):
If you want run-time construction of run-time chosen values, you'll need to use
dynfunctions that can be closures, and to let the function reference itself is a little tricky to set up:The use of weak reference-counting here prevents
omega()from being a memory leak, because strong references are only produced when the structure is traversed. (It would be a memory leak if youupgrade()d theWeaktoRcbefore constructing the closure instead of inside it.)Note that these options involving functions are “lazy” but they are not memoizing. That would be possible but have additional work, and it would require adding a garbage collector library if you want to memoize a cyclic structure (as opposed to merely instantiating as many identical nodes of the infinite list as you traverse).
All this said, if you want to work with infinite lists in Rust, a much more idiomatic and flexible way to do that is to define them as iterators. An
Iterator<()>will work as a Peano number, andomegaisstd::iter::repeat(()).