Today I wrote and then fixed a bug that caused my program to enter an infinite 
loop for reasons I don't understand.

The program is the output display formatting for a prototype relational lambda 
calculus interpreter. First I took my two structs, Lam and App (using symbols 
for variables), and implemented the gen:custom-write interface for both, 
essentially following the example in the documentation:


#lang racket

(define-struct Lam (var body)
  #:methods gen:custom-write [(define write-proc (λ (v port mode)
                                                   (write-lam v port mode)))])
(define-struct App (func arg)
  #:methods gen:custom-write [(define write-proc (λ (v port mode)
                                                   (write-app v port mode)))])

(define (write-lam v port mode)
  (define recur (make-recur port mode))
  (fprintf port "λ~a." (symbol->string (Lam-var v)))
  (recur (Lam-body v)))

(define (write-app v port mode)
  (define recur (make-recur port mode))
  (write-string "(" port)
  (recur (App-func v))
  (write-string " " port)
  (recur (App-arg v))
  (write-string ")" port))

(define (make-recur port mode)
  (define aux (case mode
    [(#t) (lambda (v) (write v port))]
    [(#f) (lambda (v) (display v port))]
    [else (lambda (v) (print v port mode))]))
  (λ (v)
    (if (symbol? v)
        (write-string (symbol->string v) port)
        (aux v))))


It worked fine. Then I defined two new structs, Lam* and App*, representing how 
the written notation groups consecutive lambdas and consecutive applications 
together to save parentheses. I also wrote procedures to convert from the 
simple representation to the new one. Finally, I implemented gen:custom-write 
for the new structs:


(define-struct Lam* (var* body) #:transparent
  #:methods gen:custom-write [(define write-proc (λ (v port mode)
                                                   (write-lam* v port mode)))])

(define-struct App* (body*) #:transparent
  #:methods gen:custom-write [(define write-proc (λ (v port mode)
                                                   (write-app* v port mode)))])

(define (write-lam* v port mode)
  (define recur (make-recur port mode))
  (define var-str (string-append* (map symbol->string (Lam*-var* v))))
  (fprintf port "λ~a." var-str)
  (recur (Lam*-body v)))

(define (write-app* v port mode)
  (define recur (make-recur port mode))
  (define (space-recur v)
    (write-string " " port)
    (recur v))
  (define body* (App*-body* v))
  
  (write-string "(" port)
  (recur (car body*))
  (map space-recur (cdr body*))
  (write-string ")" port))

(define (exp->exp* e)
  (match e
    [(Lam _ _)
     (define-values (var* body) (lam->var*+body e))
     (Lam* var* body)]
    [(App _ _)
     (App* (reverse (app->body* e)))]
    [else e]))

(define (lam->var*+body e)
  (match e
    [(Lam v (and b (Lam _ _)))
     (define-values (var* body) (lam->var*+body b))
     (values (cons v var*) body)]
    [(Lam v b)
     (values (list v) (exp->exp* b))]))

(define (app->body* e)
  (match e
    [(App (and e1 (App _ _)) e2)
     (cons (exp->exp* e2) (app->body* e1))]
    [(App e1 e2)
     (list (exp->exp* e2) (exp->exp* e1))]))


Since I knew that the new method implementations would be pretty similar to the 
old ones, I followed my usual bad habit of cutting and pasting and then making 
changes. And as happens more than I like to admit, I missed something. 
Specifically, in the last line of write-lam*, where you now see Lam*-body, I 
left it as Lam-body. When I tried displaying some simple test data, it went 
into an infinite loop. When I tried to investigate with the debugger, I learned 
that you can't break out of a loop in the debugger.

Anyway, long-story->short, I fixed the error, but now I'm puzzled. Shouldn't 
the program have stopped with an error message when Lam-body was applied to a 
non-Lam?

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to