smlmlmosml

Finding a value in a function represented environment


When it came to finding a value in a bst env all I had to do was compare the value I was looking for with the root value at a node

type 'a tenv = (name * 'a) btree

exception NotFound of name
fun find compare name Leaf = raise NotFound name 
| find compare name (Node (lt, (key, value), rt)) = 
  case compare(name, key) of
    LESS => find compare name lt
  | GREATER => find compare name rt
  | EQUAL => value

But in a function represented env instead of a bst with nodes and leafs the find function is of type

name * 'a fenv -> 'a

and

type 'a fenv = name -> 'a

I get the general idea of the function but I'm confused as to how I would traverse the environment looking for the name. Bst has a node and a tree like structure. Can someone just give an explanation if possible?

EDITED IN

My working implementation is as such

exception NotFound of name
val Empty = fn name => raise NotFound name

fun Find(name, env) = env name

fun Bind(name, data, rho) = fn key => if key = name then data else rho 
key 

Solution

  • So an environment is now represented as a function that takes a name and either returns its value in the environment or raises an exception.
    This function is going to be a composition of functions, and you "traverse" it by applying functions that represent older environments.
    (This sounds more complicated than it is, but it can take a while to wrap your head around it.)

    You can create the empty environment by writing a function that takes a name and raises an exception:

    val empty = fn n => raise NotFound n
    

    Finding things is much shorter than a tree lookup, since the environment already is that function:

    fun find n env = env n
    

    What remains is insertion:

    fun insert (key, value) env = ... what?
    

    It has to be a function that takes a name, since that's what an environment is

    fun insert (key, value) env = fn n => ... what?
    

    If n is the same as key, that function should return value:

    fun insert (key, value) env = fn n => if n = key then value else ... what?
    

    n might be found in the rest of the environment, so we apply that function in order to look for it there:

    fun insert (key, value) env = fn n => if n = key then value else env n
    

    And that's, as they say, it.

    In a sense, the "traversal" code has moved from the lookup function to the insertion function.

    Test:

    - val env = insert ("hi", 23) empty;
    val env = fn : string -> int
    - find "hi" env;
    val it = 23 : int
    - find "hello" env;
    
    uncaught exception NotFound
      raised at: ...
    - val env2 = insert ("hello", 999) env;
    val env2 = fn : string -> int
    - find "hello" env2;
    val it = 999 : int
    - find "hi" env2;
    val it = 23 : int
    

    As you can see, representing things as functions can be extremely compact.


    In order to see what's happening, let's expand the first example:

    val env = insert ("hi", 23) empty
    

    Which is the same as (expanding the definition of insert):

    val env = fn n => if n = "hi" then 23 else empty n
    

    Successful lookup:

    find "hi" env
    

    is

    env "hi"
    

    which is

    (fn n => if n = "hi" then 23 else empty n) "hi"
    ->
    if "hi" = "hi" then 23 else empty n
    -> 
    23
    

    Failure:

    find "hello" env
    ->
    (fn n => if n = "hi" then 23 else empty n) "hello"
    ->
    if "hello" = "hi" then 23 else empty "hello"
    ->
    empty "hello"
    ->
    raise NotFound "hello"
    

    Exception-handling example:

    If you don't handle the exception, you will get an "uncaught exception" error, as in the example above.

    You need to handle the exception in the code that uses find.
    A trivial example:

    fun contains n env = let val _ = find n env
                         in true
                         end
                         handle NotFound nm => false
    
    
    - contains "hello" env;
    val it = false : bool
    - contains "hi" env;
    val it = true : bool