So8res
So8res

Reputation: 10386

Partial expansion of code in scheme

I have a need to partially expand scheme code without completely evaluated. I'd like a function that takes something like this:

'(let [(my-number 8)
       (my-function (lambda args 'value))]
  (cond
    ((> my-number 10) (my-function 'x 'y 'z))
    ((= my-number 10) (my-function 'a 'b 'c))
    (else my-number)))

and turns it into this:

'(cond
  ((> 8 10) 'value)
  ((= 8 10) 'value)
  (else 8))

In other words, I want something that expands definitions, lets, letrecs, etc. without doing any dangerous evaluation. I plan to do some static analysis on some varied scheme code, and it would be nice if all the code is in a relatively normalized form. I'd like to do as much expansion as possible without risking any I/O.

What this entails is basically writing a scheme evaluator. I'd rather not. Is there any scheme functions that help me do this out of the box?

I should clarify that I don't have control over the input. I'm given the input as-is and I've got to analyze it; I'd prefer to normalize it before doing my analysis. That's what I'm trying to achieve here. It's not possible for me to re-write the input by hand to make life easier.

I'm using racket, but unfortunately my code has to run with #lang scheme.

Upvotes: 3

Views: 234

Answers (1)

Óscar López
Óscar López

Reputation: 236122

Perhaps expand is what you're looking for? It will not produce an output as the one in the question, but it will:

Expand all non-primitive syntax in top-level-form, and return a syntax object for the expanded form that contains only core forms, matching the grammar specified by Fully Expanded Programs

Here's an usage example:

(define src
  '(let [(my-number 8)
         (my-function (lambda args 'value))]
     (cond
       ((> my-number 10) (my-function 'x 'y 'z))
       ((= my-number 10) (my-function 'a 'b 'c))
       (else my-number))))

(syntax->datum
 (parameterize ([current-namespace (make-base-namespace)])
   (expand (datum->syntax #f src))))

With this output:

(let-values (((my-number) '8) ((my-function) (lambda args 'value)))
  (if (#%app > my-number '10)
    (let-values () (#%app my-function 'x 'y 'z))
    (if (#%app = my-number '10)
      (let-values () (#%app my-function 'a 'b 'c))
      (let-values () my-number))))

Notice that if we remove the syntax->datum conversion, the value returned by expand will be a syntax object, which could be more useful for performing the analysis you have in mind.

Upvotes: 1

Related Questions