Sun Apr 26 12:39:23 CEST 2009

zipper dictionary

So I abstracted the pattern into an abstract data structure.  The key
seems to be that instead of postponing the "collapse" operation to a
postprocessing step, it should be accessible to users of the library
so the current entry can be collapsed and tagged.

Let's apply this to locals to see what's necessary:

   - grab the current code and return it as an expression

   - install a new collapse routine, which uses the default collapse
     as an embedded operation.

So the dictionary needs to store the default collapse.

It's probably best to make sure the internal state of the dictionary
is never observable: users of the dictionary can only put stuff
inside, but never take out.  The semantics function (packer) itself
should be observable, just like the result of its application to the
current entry.

;; Locals.  Transform object + semantics into new semantics.
(define (locals-obj+pack->pack obj pack)
  (lambda (instructions)
    `(lambda (p)
       (let ((p+ (apply ,obj p)))
         (let ((top (car p+))
               (p++ (cdr p+)))
           (apply ,(pack instructions) p++))))))

It looks like this works.

Time to use it in the rpn parser.

First, remove code tagging.  That's about how the structure is used
and it can be hidden in the semantics.

Wait: nested locals.  It should have a proper semantics.

Hmm... it doesn't do what I expect.

Using the default semantics will not nest the locals properly (earlier
ones no longer visible).  Using the current replaced semantics will
apply the first program twice.

Using the current semantics:

  (lambda (p)
    (let ((p+
            (lambda (p)
              (let ((p+ (apply (program: 10000) p)))
                (let ((*OUTER* (car p+)) (p++ (cdr p+)))
                  (apply (program: 20000) p++))))
      (let ((*INNER* (car p+)) (p++ (cdr p+)))
         (lambda (p)
           (let ((p+ (apply (program: 10000) p)))
             (let ((*OUTER* (car p+)) (p++ (cdr p+)))
               (apply (program: 30000) p++))))

This is not correct as (program: 10000) gets applied twice.  To make
sure let's alpha-convert.

  (lambda (p0)
    (let ((p1
            (lambda (p2)
              (let ((p3 (apply (program: 10000) p2)))
                (let ((*OUTER* (car p3)) (p4 (cdr p3)))
                  (apply (program: 20000) p4))))
      (let ((*INNER* (car p1)) (p5 (cdr p1)))
         (lambda (p6)
           (let ((p7 (apply (program: 10000) p6)))
             (let ((*OUTER* (car p+)) (p8 (cdr p7)))
               (apply (program: 30000) p8))))

Damn.. i miss the intution and i can't make the algebra make sense..

I'm probably confusing two things.  The problem is that normal code
nesting reverses the order, but locals nesting is the same order as in

So.. Is it possible to somehow change the code so that (a b c)
corresponds to (a (b (c _))) instead of (c (b (a _)))?

Yes.. It's CPS.

So, maybe I should use cps.. When I do that, I do want to know how
good things are optimized away though, to make sure representation is
a bit decent.