The model of environment is one of the most important part of this software. It determines the background the commands are evaluated in. We have chosen to implement it in a straightforward way: using lists. In our model, an environment is composed of a main list, the-global-environment, enclosing various frames which, in turn, enclose pairs of variable and values.
Back to our concrete example, (lookup-variable-value V env) is going to look for the value of V in the environment env. Env could be any valid environment, but it is the so called the-global-environment. This specific entity is initialized at startup and contains the underlying Scheme primitives (+,-, car ...), as well as AriNET's primitives. The value of V in this environment, is <procedure:me>, a procedure object issued from the definition of V. Evaluating (defvariable V) executed the (make-variable) function from the arinet.scm file:
(define (make-variable)
(let ((value '())
(informant '())
(constraints '()))
(define (set-my-value! new-value setter)
(cond ((not (has-value? me))
(set! value new-value)
(set! informant setter)
(for-each-except setter inform-about-value constraints))
((> (abs (- value new-value)) eps)
(ErrorMsg (string-append "Contradiction "
(number->string value)
"="
(number->string new-value))
'user))
(else #t)))
(define (forget-my-value! retractor)
(cond ((or (equal? retractor informant)
(equal? retractor 'Passpartout))
(set! informant '())
(set! value '())
(for-each-except retractor
inform-about-no-value
constraints))
;(else 'done)
(else (ErrorMsg "Unable to forget the value" 'user))))
This important function creates an AriNET variable which will be stored in the the-global-environment. This variable is different form a Scheme variable, as it is able to evolve together with the modeled equation.
Coming back to where the recursion originally started
(define (ari-eval-equation expr env)
(equalizer (prefix->arinet (left-expr expr) env)
(prefix->arinet (right-expr expr) env)))
the right-part of the initial equation, i.e (* (* pi (sqr 15)) h), is evaluated in the same way. When both parts of the equation have been evaluated the system creates a so called equalizer box, a special component of the file arinet.scm:
(define (equalizer b1 b2)
(define (process-new-value)
(cond ((has-value? b1) (set-value! b2 (get-value b1) me))
((has-value? b2) (set-value! b1 (get-value b2) me))))
(define (process-forget-value)
(forget-value! b1 me)
(forget-value! b2 me)
(process-new-value))
(define (me request)
(cond ((equal? request 'i-have-a-value) process-new-value)
((equal? request 'i-lost-my-value) process-forget-value)
(else (ErrorMsg "Unknown request -- EQUALIZER" 'code))))
(connect b1 me)
(connect b2 me)
me)
It links the right-part of our equation (* (* pi (sqr 15)) h) together with the left part V. The same process is done when evaluating any of the 1ary or 2ary operations described in section 2.4.3.
The creation of such ``binded boxes'' is the hearth of AriNET's concept. This enables the program to update every single part of the equation, each time a new value is found. It is exactly what happens when evaluating:
(set-value! pi 3.14159 'user) (set-value! r 15 'user) (set-value! V 450 'user)
The function set-value! (in arinet.scm) assigns a new values to pi,r and V only, but because these values are binded together using ``boxes'' the value of h becomes available as well, the equation is solved!
> (get-value h) 0.636620310097753