[racket] Reading Graph Structure: read: #..= expressions not allowed in read-syntax mode (??)

From: Eli Barzilay (eli at barzilay.org)
Date: Mon Jun 6 10:56:40 EDT 2011

25 minutes ago, Marijn wrote:
> My understanding is that it is a finite data structure that refers
> to itself. It is supposed to represent 3 nodes/links of a doubly
> linked list where each node points to its neighbours or #f, so
> really it should only be 3 _dl's big...

Yes, I know what you meant...  Here's a simpler demonstration:

  #1=(cons 1 #1#)

But the cyclic thing here is *not* the data, it's the code that is
cyclic.  IOW, compilers see that as

  (cons 1 (cons 1 (cons 1 (cons 1 (cons 1 ...)))))

so they're essentially compiling an infinite piece of code, and the
stack overflows and infinite loops are an obvious result.  It's true
that in *some* cases you can find how to compile it into working code.
In Racket that example would involve some use of `make-reader-graph',
and your example will need to have mutable fields or some way to
initialize field values in a circular way.  (Search the docs for
`shared'.)  Doing that is also questionable for another reason -- for
example, if I write:

  (define x1 #1=(cons 1 (lambda () #1#)))
  (define x2 #2=(cons 1 (lambda () (cons 1 (lambda () #2#)))))

then the two values that I'd supposedly get are different -- which
you'd see with `eq?'.  But that means that compiling code depends on
the identity of the code itself, not just on the code.

In any case, it should be obvious that it's really not a simple thing
to compile.  There are old legends about lisp implementations which
would compile even more of these things, so you could have an infinite
loop like:

  #1=(begin (printf "hey\n") #1#)

and it would compile the code to the right thing, and with enough
punctuations you could get generic gotos of some limited kind (imagine
using them across functions...).  But those implementations were
dropped into a volcano a good while ago.  (And I can imagine that a
few lispers jumped right in shouting "my prrrecious".)

[It's still used in CL in two cases: (a) inside a quoted expression,
(b) with tricks like (let ((#1=#:foo)) (* #1# #1#)) where `#:foo' in
CL is read as a fresh unintered symbol, so the #1# is the only way to
refer to it.]

> Alternatives are to use a letrec with `delay' on `left and `right'
> members, but then a new accessor that wraps `force' will have to be
> used everywhere.  Finally, mutation can be used to connect links
> together in the desired way.  Maybe I'm trying too hard to avoid
> this simple fix?

Yes, that's another way to see why it's not allowed...  You need to do
what you wanted the compiler to do, and it's not straightforward.
(And again, see `shared'.)

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!

Posted on the users mailing list.