Environment model

 

 

So let's start section with some basic adminstrative information. Students can rate us at  http://www.engineering.cornell.edu/taeval/survey.cfm

 

So we need to talk about the environment model.  The enviroment model is a formal method for reasoning about programs.  We want to use the envrinment model for several reasons.  The evironment model:

 

    1) mirrors real interpreter desgin

    2) formalizes fun cleanly

    3) simplifies reasoning about refs

 

We will try to de-emphasize the imperative nature of the environment model. This means we need to try to stay away from presenting environment diagrams as something that we construct imperatively.  Traditionally we have said,

 

"val x=1+1"

 

means we evaluate 1+1 then draw a box and put x: 3 in it.  This semester we will have a more functional emphasis.  The notation that we will use will hopefully convey this to the students.  Unfortunately, the imperative way of building environment diagrams is part of what makes them simple to work with, hence useful.  I guess the moral here is to separate the construction and the idea behind it.

 

Jeff Vinocur's notes on the environment model provide a great overview in the imperative style of drawing environments:

http://www.cs.cornell.edu/courses/cs312/2002sp/handouts/environment-model.html

 

To look at things more functionally, I would like to introduce a few definitions:

 

   eval: expression * environment -> value

   bind: enviroment * variable * value -> environment

 

These guys are metafunctions (not ML!) and don't have time to offer full definitions.  However their behavior follows naturally from the SML's language semantics.

 

I will use [] to represent a frame and [[]] to represent the top-level environment's double frame. So

            

[[]]<--[x:3]<--[y:2]<--[x:1]

 

is the environment where y is bound to 2 and x bound to 1 shadows x bound to 3.

 

I'm going to use {} and <> as parentheses. This is intended to make parentheses matching visually less painful, and not to convey any extra meaning.

 

Examples

 

Very simple examples:

 

1) evaluate: let val x = 40+2 in x end

 

    - eval(let val x = 40+2 in x end, [[]])

    - eval(x, bind{ [[]], x, eval(40+2, [[]]) } )

                                         (* same as evaluating the in clause in

                                          * the environment created by binding

                                          * x to the value found by evaluating

                                          * 40+2 in the environment [] *)

    - eval(x, bind{ [[]], x, 42} )

    - eval(x, [[]]<--[x: 42])

    - 42                                  (* we evaluate x by looking it up in the current environment*)

 

2) evaluate        let val x = (

                 let val x = 13 in 300 + x end )

                                     in

   x - 1

             end

 

    - eval( let val x = (

                             let val x = 13 in 300 + x end )

                         in

                           x - 1

             end

           , [[]])

 

    - eval( x-1, bind{ [[]], x, eval <let val x = 13 in 300 + x end, [[]]> })

 

    - eval( x-1, bind{ [[]], x, eval <300 + x, bind{ [[]], x, eval(13, [[]])}> })

 

    - eval( x-1, bind{ [[]], x, eval <300 + x, bind{ [[]], x, 13}>})

 

    - eval( x-1, bind{ [[]], x, eval <300 + x, [[]]<--[x: 13]>})

 

    - eval( x-1, bind{ [[]], x, eval <300 + 13, [[]]<--[x: 12]>})

 

    - eval( x-1, bind{ [[]], x, 313})

 

    - eval( x-1, [[]]<--[x: 313])

 

    - eval(313-1, [[]]<--[x: 313])

 

    - 312

 

 

Looking above, we can only say, "the horror, the horror".  To keep the paper work under control we need to scale the formalism back.  However, the above was useful. In particular, it demonstrates that environments, like lists, are really not mutable, even if though it's sometimes easy to forget.

 

A few more examples, omitting the steps:

 

3)

 

let

   val x = 4

   val f = fn a => a+x

   val x = 2

in

   f x

end

 

is equivalent to:

 

let val x = 4

    in let val f = fn a => a+x

in let val x = 2

                   in

                       f x

                  end

            end

    end

 

Which builds environment:

 

[[]]<--[x: 4]<--[f :+]<--[x: 2]

            ^        |         *

            |        |

            +-------oo

                    p: a

                    b: a+x

 

Evaluating f(x) in this context (the * denotes the top of the environment)

yields f 2 =  x+2 = 4+2 = 6.

Why did we use the binding of x: 4?