I feel a little stupid for asking this, but I'm currently learning functional programming and completed an exercise on creating singly linked lists and it just got me thinking, is it even possible to create an immutable doubly linked list?
Suppose the list A :: B, at time of construction, A needs to know about B, but B also needs to know about A. I've been doing this in Scala, so I'm not sure if it's specific to Scala, but I can't picture how that would work.
I'm not looking for a substitute as I don't need this for anything, I'm just curious.
Yes, it's possible. It is usually not done though, because unlike a singly linked list, a double linked list does not have any substructures that could be reused when, for example, one element is removed. Moreover, such a list doesn't seem to do anything what an immutable
Vector
cannot do.Nevertheless, let's write it down, because it's fun.
Simplified problem: circular two-element "list"
As a warm-up, take a look at the simplified problem: a circular two-element "list" with two nodes referencing each other:
This indeed works, and we can build this little two-node data structure, and run in circle on it for a few million iterations:
Output:
What the loop demonstrates is: this is an actual data structure, not some family of weirdly nested functions that blow the stack after accessing the elements a few times.
Immutable double-linked list
I've decided to represent the list by nodes connected with double links, and two explicit
Nil
-elements at both ends:The
apply
-part is mostly irrelevant, I added it only so I can inspect and print the content later. The interesting question is: how can we actually instantiate such a list? Here is a way to convert a single linked list into a double linked list:What happens here is essentially the same trick as with the two-element-ring above, but repeated multiple times. We just keep joining pieces in the same way we joined the two half-rings, except that here we are first joining small
Cons
-elements to long tails of a list, and finally join aLeftNil
with the firstCons
.Again, a little demo, an "iterator" that keeps running on the list back and forth for a few millions iterations, and occasionally prints the current element:
Remark: I don't find the recursive
build
-method particularly intuitive, I couldn't write it down directly without scribbling on a piece of paper for a few minutes. To be honest, I'm still a bit surprised every time it works.