Reputation: 518
So I'm familiar with while loops in other languages, but am having trouble getting it to work in Racket. The best I've been able to accomplish is either getting the loop to run once (more like an if statement) or hitting an infinite loop.
Here is the code for running once:
;; Evaluates a loop.
;; When the condition is false, return 0.
;; There is nothing special about zero -- we just need to return something.
(define (eval-while c body env)
(if (false?(car(evaluate c env)))
(cons 0 env)
(evaluate body env))
)
And here's my other attempt with an infinite loop:
(define (eval-while c body env)
(if (evaluate c env)
(eval-while c body (cdr(evaluate body env)))
(cons 0 env))
)
Here's some other possibly relevant code (the interpreter portion):
(define (evaluate prog env)
(match prog
[(struct sp-val (v)) (cons v env)]
[(struct sp-while (c body)) (eval-while c body env)]
[_ (error "Unrecognized expression")]))
Any help is much appreciate!
EDIT:
Here's a more complete version of the code.
Test case:
(evaluate (sp-seq (sp-assign "x" (sp-val 0))
(sp-seq (sp-assign "y" (sp-val 10))
(sp-while (sp-binop < (sp-var "x") (sp-var "y"))
(sp-assign "x" (sp-binop + (sp-var "x") (sp-val 1))))
))
empty-env) ;'(0 . #hash(("y" . 10) ("x" . 10)))
And more main evaluations:
[(struct sp-binop (op exp1 exp2)) (eval-binop op exp1 exp2 env)]
[(struct sp-assign (var exp)) (eval-assign var exp env)]
[(struct sp-var (varname)) (cons (hash-ref env varname) env)]
Please let me know if I should also include their definitions.
EXTRA ADDITION eval-assign:
(define (eval-assign var exp env)
(cons (car(evaluate exp env))(hash-set env var (car(evaluate exp env))))
)
Upvotes: 1
Views: 906
Reputation: 31147
Is the convention that all evaluator functions return a pair of the value and the environment? If so, then this might work:
(define (eval-while c body env)
(if (evaluate c env) ; if c is true
(begin ; then
(evaluate body env) ; 1) evaluate body
(eval-while c body env)) ; 2) loop
; else
(cons 0 env))) ; return 0 (and environment)
Note that the call (eval-while c body env)
is a tail call. That means that there is no buildup of evaluation context.
UPDATE
From the source of eval-assign
I can see that the environment is represented as an immutable hash table. Therefore the loop needs to use the new environment.
Try this:
(define (eval-while c body env)
(if (evaluate c env) ; if c is true
(match (evaluate body env) ; then evaluate body
[(cons value new-env) ; grab the new environment
(eval-while c body new-env)]) ; loop using new env
(cons 0 env))) ; return 0 (and environment)
Also: Insert a (displayln env)
in eval-while
to check that the environment is updated.
Upvotes: 3