Site hosted by Angelfire.com: Build your free website today!

Local procedures with logo

Return

With UCBLOGO all procedures are global.
But variables may be local .
To implement local procedures we can attach procedures  to variables. 
The  actuai procedure name is genereted by gensym which genereates unique names. 
The procedures are global but there access is local.

A procedure name is created  as local variable and  the procedure  localdefine generates a unique 
procedure name using gensym and attach the procedure's name to the local variable.
The procedure localrun execute the procedure with its parameters.
When the procedure is no more used we erase its local name.

to Testlocalprocedure 
local "proc 
localDefine "proc [[x][pr :x]]
localrun [ proc [here proc1]]
embededproc
er :proc
end

To see that the same procedure name is local we define  a different procedure with the same name 
inside  the procedure embededproc which is called  by Testlocalprocedure.


to embededproc
local  "proc
localdefine "proc [[x][(pr "----- :x "-----)]]
localrun  [proc [here proc2]]
er :proc 
end

? testlocalprocedure
here proc1
----- here proc2 -----


If we don't define a  local procedure in embededproc the procedure defined in Testlocalprocedure (which is under
the scope of the variable proc) is used.


to embededproc
,local  "proc
,localdefine "proc [[x][(pr "----- :x "-----)]]
localrun  [proc [here proc2]]
er :proc 
end

? testlocalprocedure
here proc1
here proc2

Procedure as black box
Locales   procedures are needed to hide procedures used as tool in a main procedure.

We are only interested only the action of the main procedure.The tools are defined as local procedures 
inside the body of the main procedure.

Example from Structure and Interpretation of Computer Programs,  1.1.8  Procedures as Black-Box Abstractions.


Internal definitions and block structure

We have one kind of name isolation available to us so far: The formal parameters of a procedure are local inside the body of the procedure. 
The square-root program illustrates another way in which we would like to control the use of names. 
The existing program consists of separate procedures:

(define (sqrt x)
  (sqrt-iter 1.0 x))
(define (sqrt-iter guess x)
  (if (good-enough? guess x)
      guess
      (sqrt-iter (improve guess x) x)))
(define (good-enough? guess x)
  (< (abs (- (square guess) x)) 0.001))
(define (improve guess x)
  (average guess (/ x guess)))

The problem with this program is that the only procedure that is important to users of sqrt is sqrt. 
The other procedures (sqrt-iter, good-enough?, and improve) only clutter up their minds. 
They may not define any other procedure called good-enough? as part of another program to work together 
with the square-root program, because sqrt needs it. The problem is especially severe in the construction 
of large systems by many separate programmers. 
For example, in the construction of a large library of numerical procedures, many numerical functions are 
computed as successive approximations and thus might have procedures named good-enough? and improve 
as auxiliary procedures.
We would like to localize the subprocedures, hiding them inside sqrt so that sqrt could coexist with other successive approximations, each having its own private good-enough? procedure. To make this possible, 
we allow 
a procedure to have internal definitions that are local to that procedure. For example, in the square-root 
problem we can write

(define (sqrt x)
  (define (good-enough? guess x)
    (< (abs (- (square guess) x)) 0.001))
  (define (improve guess x)
    (average guess (/ x guess)))
  (define (sqrt-iter guess x)
    (if (good-enough? guess x)
        guess
        (sqrt-iter (improve guess x) x)))
  (sqrt-iter 1.0 x))

Such nesting of definitions, called block structure, is basically the right solution to the simplest name-packaging problem. But there is a better idea lurking here. 


(define (sqrt x)
  (define (good-enough? guess)
    (< (abs (- (square guess) x)) 0.001))
  (define (improve guess)
    (average guess (/ x guess)))
  (define (sqrt-iter guess)
    (if (good-enough? guess)
        guess
        (sqrt-iter (improve guess))))
  (sqrt-iter 1.0))


UCBLogo version:

to sqrtnew :x
;Assuming square abs average already defined
local "good.enough
localdefine "good.enough [[guess x] [op  (abs (( square :guess) - :x  ) )< 0.0001 ]]
local "improve
localdefine "improve [[guess x] [op  average :guess (:x / :guess) ]]
local "sqrt.iter
localdefine "sqrt.iter [[guess x] [op ifelse (localrun [good.enough :guess :x] ) [ :guess][ localrun [sqrt.iter (localrun [improve :guess :x] ):x]]]]
localmake "temp ( round ( 10000 * ( localrun  [sqrt.iter 1.0 :x] ) ) ) / 10000 
er thing "sqrt.iter 
er thing "good.enough
er thing "improve
op :temp
end

? show procedures
[abs average buryall created embededproc erlocals localdefine localrun mytest showt sqrtiter sqrtnew sqrtnew2
 square testlocalprocedure unburyall]
? pr sqrtnew 2
1.4142
? show procedures
[abs average buryall created embededproc erlocals localdefine localrun mytest showt sqrtiter sqrtnew sqrtnew2
 square testlocalprocedure unburyall]
?
We see that after running sqrtnew the procedures are the same then before

In addition to internalizing the definitions of the auxiliary procedures, we can simplify them. 
Since x is bound in the definition of sqrt, the procedures good-enough?, improve, and sqrt-iter, which are 
defined internally to sqrt, are in the scope of x. 
Thus, it is not necessary to pass x explicitly to each of these procedures. Instead, we allow x to be a
free variable in the internal definitions, as shown below.
Then x gets its value from the argument with which the enclosing procedure sqrt is called. 
This discipline is called lexical scoping.27

(define (sqrt x)
  (define (good-enough? guess)
    (< (abs (- (square guess) x)) 0.001))
  (define (improve guess)
    (average guess (/ x guess)))
  (define (sqrt-iter guess)
    (if (good-enough? guess)
        guess
        (sqrt-iter (improve guess))))
  (sqrt-iter 1.0))
 
Ucblogo version:

to sqrtnewwithoutx :x
;Assuming square abs average already defined
local "good.enough
localdefine "good.enough [[guess ] [op  (abs (( square :guess) - :x  ) )< 0.0001 ]]
local "improve
localdefine "improve [[guess ] [op  average :guess (:x / :guess) ]]
local "sqrt.iter
localdefine "sqrt.iter [[guess x] [op ifelse (localrun [good.enough :guess ] ) [ :guess][ localrun [sqrt.iter (localrun [improve :guess ] ):x]]]]
localmake "temp ( round ( 10000 * ( localrun  [sqrt.iter 1.0 :x] ) ) ) / 10000 
er thing "sqrt.iter 
er thing "good.enough
er thing "improve
op :temp
end





Return






.