The LSM gives us one model of a state machine in functional form. We will use it to define “global” functions in an applicative (eager evaluation) functional style.
The global environment is part of the m-state. Adding named functions to it is done by creating a binding and making a new global environment, which is passed to the next state to become the new global environment. An LSM level command (def <name> <expression>) is recognized by the generator for the next m-state. The def command binds <name> to the unevaluated <expression>, and adds the binding to the global environment. The result value is the empty list.
next-m-state = (lambda (m-state i-state) (cond ((eq (car i-state) (quote def)) (cons (quote ()) (add-to-env (make-binding (car (cdr i-state)) (car (cdr (cdr i-state))) ) (cdr m-state) ) ) ) (t (cons (eval i-state (cdr m-state)) (cdr m-state) ) ) ) ) add-to-env = (lambda (binding env) (cons binding env) ) make-binding = (lambda (var value) (cons var value) )
The following script will test that a globally defined variable can be evaluated as a variable, or as a function if it is bound to a function definition…
(def f1 (lambda (a b) (cons a b))) f1 (f1 (quote (x y z)) (quote (a b c)))
My base (assembly language) system still requires that nonprimitive function definitions be named in the a-list used as an argument to eval0. When the LSM interpreter is invoked, the remaining input is interpreted under the environment set by the LSM interpreter, rather than the environment of the base system. The LSM interpreter promotes the mixing of evaluation and persistent definition, whereas the base system promotes the separation of evaluation and persistent definition.