[plt-scheme] self-referential data structures

From: Henk Boom (henk at henk.ca)
Date: Thu Mar 5 23:15:53 EST 2009

2009/3/5 Stephen Bloch <sbloch at adelphi.edu>:
> However, there are more complicated self-referential data types that are
> difficult to do without mutation.  For example, consider
> (define biglist (list 10 9 8 7 6 5 4 3 2 1 0))
> (define partlist (rest (rest (rest (rest biglist)))))
> From "partlist", you can easily get the 5th element of the original list, or
> move forward to the the 6th element and so on... but there's no way to "move
> backward" through the original list to see the 3rd element of the original
> list, because "partlist" doesn't contain that information.  For some
> applications it's very useful to be able to move both backward and forward
> through a large list, and the usual data structure to do that is called a
> "doubly linked list".  Since the 5th element of a list has to "know" about
> both the 4th and 6th elements, both of which have to "know" about the 5th,
> the usual way to build a doubly linked list is to create the 6th element,
> then create the 5th element referring to it, then MUTATE the 6th element so
> that it knows about the 5th element in turn, then create the 4th element
> referring to the 5th element, then MUTATE the 5th element so  it knows about
> the 4th element, and so  on.  This is difficult to do without mutation.

You could also do something like this:

; file dlist.ss
#lang scheme/base

(provide dlist previous next current)

(define-struct triplet (previous current next))

(define (dlist x . xs)
  (make-triplet '() x xs))

(define (previous dlist)
  (make-triplet (cdr (triplet-previous dlist))
                (car (triplet-previous dlist))
                (cons (triplet-current dlist)
                      (triplet-next dlist))))

(define (next dlist)
  (make-triplet (cons (triplet-current dlist)
                      (triplet-previous dlist))
                (car (triplet-next dlist))
                (cdr (triplet-next dlist))))

(define current triplet-current)

; repl
> (define biglist (dlist 10 9 8 7 6 5 4 3 2 1 0))
> (define partlist (next (next (next (next biglist)))))
> (current partlist)
> (define going-back (previous (previous partlist)))
> (current going-back)

I used a data structure like this for a Turing Machine simulator I
wrote a few years ago, it implements a tape as two stacks, and can be
simply extended to support cheap functional update. In my use of it,
though, the tape was boundless, so I was using bottomless stacks.


Posted on the users mailing list.