Scheme rewrite let* as nested unary lets

2019-09-03 23:02发布

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.

2条回答
虎瘦雄心在
2楼-- · 2019-09-03 23:53

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.

查看更多
3楼-- · 2019-09-04 00:03

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.

查看更多
登录 后发表回答