Skip to content

Instantly share code, notes, and snippets.

@kmicinski
Last active November 15, 2023 19:40
Show Gist options
  • Save kmicinski/f3b92ace3a38854eaaf42a945df30537 to your computer and use it in GitHub Desktop.
Save kmicinski/f3b92ace3a38854eaaf42a945df30537 to your computer and use it in GitHub Desktop.
#lang racket
(define (expr? e)
(match e
[(? number? n) #t]
[(? symbol? x) #t]
[`(λ (,(? symbol? x)) ,(? expr? e)) #t]
[`(,(? expr? e0) ,(? expr? e1)) #t]
[_ #f]))
;; Closure-creating interpreter
(define (value? v)
(match v
[(? number? n) #t]
[`(closure (λ (,x) ,e) ,env) #t]
[_ #f]))
(define depth 0)
;; our interpreter takes two arguments:
;; - e, which is an expression
;; e : expr?
;; - env, which is an environment
;; env : symbol? → value? (a hash)
(define (interp e env)
(match e
[(? number? n) n]
[(? symbol? x) (hash-ref env x)]
[`(λ (,(? symbol? x)) ,(? expr? e-body))
`(closure (λ (,x) ,e-body) ,env)]
[`(,(? expr? e0) ,(? expr? e1))
(match (wrap-interp e0 env)
[`(closure (λ (,x) ,e-b) ,env+)
;; what is the importance of env+ and env being different?
(wrap-interp e-b (hash-set env+ x (wrap-interp e1 env)))])]))
(define (wrap-interp e env)
(set! depth (add1 depth))
(display (build-string depth (lambda (_) #\ )))
(display "→")
(displayln (format " ~a ~a" (pretty-format e) (pretty-format env)))
(define v (interp e env))
(display (build-string depth (lambda (_) #\ )))
(display "← returning from ")
(displayln (format " ~a ~a" (pretty-format e) (pretty-format env)))
(display (build-string depth (lambda (_) #\ )))
(displayln (format "(Return value is ~a)" (pretty-format v)))
(set! depth (sub1 depth))
v)
(wrap-interp '(λ (x) x) (hash))
(wrap-interp '((λ (x) x) (λ (x) x)) (hash))
(wrap-interp '((λ (x) (λ (y) x)) (λ (z) (λ (x) x))) (hash))
(wrap-interp '(((λ (x) (λ (y) x)) (λ (z) (λ (x) x))) (λ (x) (λ (z) z))) (hash))
@nedaAB
Copy link

nedaAB commented Nov 15, 2023

what is the importance of env+ and env being different?

So for answering this question first of all we need to answer this question: What is environment?

When we run a function in racket, it creates an environment. Actually an environment maps name of things to the actual values.

So whenever we return a lambda as a result also we're going to return the environment that lambda was created in. because that environment will be able to have all free variables in scope when we are returning the lambda.

The body in the lambda are captured in a different environment so we are showing this with env+. Our proceeding calculations for body of lambda will occur in this new environment. It is dynamic scoping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment