schemeracketletrewriting

Scheme let* as nested unary lets


As an exercise I am trying to rewrite strings representing source code for let* as nested unary lets. Here is my best effort:

(define let*→nested-unary-lets
  (match-lambda
   (`(let* (()) ,<exprs>)
   `(let () ,<exprs>))
   (`(let* ((,<var> ,<val>)) ,<exprs>)
   `(let ((,<var> ,<val>)) (let () ,<exprs>)))
   (`(let* ((,<var> ,<val>) ,<clauses>) ,<exprs>)
   `(let ((,<var> ,<val>)) (let*→nested-unary-lets '(let* (,@<clauses>) ,<exprs>))))))

The problem I am experiencing at the moment is that the pattern:

`(let* ((,<var> ,<val>) ,<clauses>) ,<exprs>)

does not match a string like:

'(let* ((a b) (c d) (e f)) <expressions>)

The term clauses matches only the second clause (c d). It seems to me that it should take all of the remaining (var val) clauses as a list ((c d) (e f)). At any rate I need it to do so.

Any advice is appreciated.

What baffles me is that exprs will match a list of expressions so I can't think of any reason why clauses wouldn't also do so.


Solution

  • You will need . ,<clauses> since you want to match the rest of the list, not just a single element. The ,<exprs> part will need to be . ,<exprs> for the same reason. I believe there is other syntax specifically for matching lists, but using . is simple and matches how lists are implemented internally.