Question

I have written a function match-rewriter that is essentially match-lambda except that it returns its argument if no match is found:

(define-syntax match-rewriter
  (syntax-rules ()
    ((_ (patt body) ...)
      (λ (x) (match x (patt body) ... (_ x))))))

Now I would like to use match-rewriter to take strings representing source code for let* and rewrite it as nested unary lets:

(define let*→nested-unary-lets
  (match-rewriter (`(let*((,<var> ,<val>) ...) ,<expr1> ,<expr2> ...)

I am really stumped over how to pattern match this. I need to return:

`(let((,<var1> ,<val1>)) let((,<var2> ,<val2>)) let((...)) ... )...) ,<expr1> . ,@<expr2>)

But the nesting has me stumped. Any advice is appreciated.


Okay, here is my best attempt:

(define let*→nested-unary-lets
  (match-rewriter
   (`(let* (()) ,<expr1> ,<expr2> ...)
   (`(let () ,<expr1> . ,<expr2>)))
   (`(let* ((,<var1> ,<val1>) (,<var2> ,<val2>) ...) ,<expr1> ,<expr2> ...)
    `(let ((,<var1> ,<val1>) (let*→nested-unary-lets 
                               '(let* ((,<var2> ,<val2>) ...) ,<expr1> . ,<expr2>)))))
   ))

But this is how it behaves:

(let*→nested-unary-lets '(let* ((a 1) (b (+ a 1)) (c (+ a b))) (displayln c))) '(let ((a 1) (let*→nested-unary-lets '(let* (((b c) ((+ a 1) (+ a b))) ...) (displayln c)))))

I am confused about the order of the arguments in:

(let* (((b c) ((+ a 1) (+ a b)))

It seems to me it should be:

(let* ((b (+ a 1)) (c (+ a b)))

Also, it would be nice if the call to let*→nested-unary-lets would execute instead of just printing as text.

Was it helpful?

Solution

Yes, you can do this; it shouldn't be too difficult. Specifically, the key idea you need here is not to try to handle the whole list at once. Instead, your patterns should separate the first binding from the rest, and then wrap one let around a recursive call to let*->nested-unary-lets.

Let me know if you have trouble formulating this.

OTHER TIPS

Here is a definition of let* in syntax-rules-like pseudocode that you can use to write your own version:

(let* ((a b) (c d) ...) body ...) === (let ((a b)) (let* ((c d) ...) body ...))
(let* () body ...) === body

You should be able to turn that into a function using match or a macro using syntax-rules.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top