extremely confused about how this "oop under-the-hood" example of a counter works - oop

here's the make-counter procedure and calls to it
(define make-counter
(let ((glob 0))
(lambda ()
(let ((loc 0))
(lambda ()
(set! loc (+ loc 1))
(set! glob (+ glob 1))
(list loc glob))))))
> (define counter1 (make-counter))
counter1
> (define counter2 (make-counter))
counter2
> (counter1)
(1 1)
> (counter1)
(2 2)
> (counter2)
(1 3)
> (counter1)
(3 4)
i can't understand why does glob behaves as a class variable, while loc behaves as an instance variable.

It may be easiest to consider when each part of the code is run. You evaluate
(define make-counter (let ((0 glob)) ...))
just once, so the let is evaluated just once. That means that there's only one binding, and its value is shared by everything within the body of the let. Now, what's in body of the let? It's a lambda function, which becomes the value of make-counter:
(lambda () ; this function is the value of make-counter
(let ((loc 0)) ; so this stuff gets execute *each time* that
(lambda () ; make-counter is called
... ;
))) ;
Now, every time you call make-counter, you evaluate (let ((loc 0)) (lambda () …)), which creates a new binding and returns a lambda function that has access to it (as well as to the global binding from outside.
So each result from calling make-counter has access to the single binding of glob, as well as to access to a per-result binding of loc.

Let us examine the program:
(define make-counter
(let ((g 0))
(lambda ()
(let ((l 0))
(lambda ()
(set! l (+ l 1))
(set! g (+ g 1))
(list l g))))))
The program illustrates how an abstraction (lambda-expression) creates
a closure that contains references to the free variables.
It would be helpful to see and inspect the free variables explicitly,
so let's pretend we want to run the program above in a language
that doesn't support lambda. In other words, let try to rewrite
the program into one that uses simpler constructs.
The first is to get rid of assignments. Let's allocate a box
(think vector of length one) that can hold one value.
An assignment can then change the value that box holds using set-box!.
; Assignment conversion: Replace assignable variables with boxes.
; The variables l and g are both assigned to
(define make-counter
(let ((g (box 0)))
(lambda ()
(let ((l (box 0)))
(lambda ()
(set-box! l (+ (unbox l) 1))
(set-box! g (+ (unbox g) 1))
(list (unbox l) (unbox g)))))))
This program is equivalent to the original (try it!).
The next step is to annotate each lambda with its free variables:
(define make-counter
(let ((g (box 0)))
(lambda () ; g is free in lambda1
(let ((l (box 0)))
(lambda () ; g and l are free lambda2
(set-box! l (+ (unbox l) 1))
(set-box! g (+ (unbox g) 1))
(list (unbox l) (unbox g)))))))
Now we are ready to replace lambda with explicit closures.
A closure holds
i) a function with no free variables
ii) values of the free variable at the time the closure was created
We will use a vector to store i) and ii).
(define (make-closure code . free-variables)
(apply vector code free-variables))
We can get the function with no free variables like this:
(define (closure-code closure)
(vector-ref closure 0))
And we can the i'th free variable like this:
(define (closure-ref closure i)
(vector-ref closure (+ i 1)))
To apply a closure one calls the function with no free variables (code)
with both the closure (which code will need to find the values of the
free variables) and the actual arguments.
(define (apply-closure closure . args)
(apply (closure-code closure) closure args))
Here are the code corresponding to the lambda1
(define (lambda1 cl) ; cl = (vector lambda1 g)
(let ((g (closure-ref cl 0))) ; g is the first free variable of lambda1
(let ((l (box 0)))
(make-closure lambda2 g l))))
Since lambda1 was a function of no arguments, the only input is the closure.
The first thing it does is to retrieve the free value g.
Note that lambda1 returns a closure: (make-closure lambda2 g l)
Here we see that when the closure for lambda2 is made the values of g and l
are preserved.
Now lambda2:
(define (lambda2 cl) ; cl = (vector lambda2 g l)
(let ((g (closure-ref cl 0))
(l (closure-ref cl 1)))
(set-box! l (+ (unbox l) 1))
(set-box! g (+ (unbox g) 1))
(list (unbox l) (unbox g))))
Finally make-counter which simply makes a lambda1-closure:
(define make-counter (make-closure lambda1 (box 0)))
We are now ready to see our program in action:
(define counter1 (apply-closure make-counter))
counter1
(define counter2 (apply-closure make-counter))
counter2
(apply-closure counter1)
(apply-closure counter1)
(apply-closure counter2)
(apply-closure counter1)
The output is:
'#(#<procedure:lambda2> #&0 #&0)
'#(#<procedure:lambda2> #&0 #&0)
'(1 1)
'(2 2)
'(1 3)
'(3 4)
This means out program works in the same way as the original.
Now however we can examine the free variables of the two counters:
> counter1
'#(#<procedure:lambda2> #&4 #&3)
> counter2
'#(#<procedure:lambda2> #&4 #&1)
We can check that the two counters share the same g:
> (eq? (closure-ref counter1 0)
(closure-ref counter2 0))
#t
We can also check that they have two different boxes containing l.
> (eq? (closure-ref counter1 1)
(closure-ref counter2 1))
#f

Related

scheme: resuming a loop after a condition has been signaled

This program is using Scheme conditions and restarts to execute a procedure 10 times in a loop, and return the number of times the procedure did succeed.
Here the procedure throws an error each times n is a multiple of 3.
For some reason, the first error (n=3) is caught but the loop fails to resume with n=4:
(define (handle! thunk)
(bind-condition-handler
'() (lambda (condition)
(display "resuming...")
(invoke-restart (find-restart 'next)))
thunk))
(let loop((n 1) (count 0))
(display n)(display #\,)
(if (> n 10) count
(handle!
(call/cc
(lambda (cc)
(with-restart
'next "restart here"
(lambda ()
(cc (loop (1+ n) count)))
#f
(lambda ()
(if (= 0 (modulo n 3))
(error n "is multiple of 3!")
(loop (1+ n) (1+ count))))))))))
I failed to find examples of conditions and restarts beyond the ones at the MIT Scheme Reference.
The solution is to move down the call/cc to the loop argument 'count' which is affected by the condition:
(let loop((n 1) (count 0))
(display n)(display #\,)
(if (> n 10) count
(handle!
(lambda()
(loop (1+ n)
(call/cc
(lambda (cc)
(with-restart
'next "restart here"
(lambda ()
(cc count))
#f
(lambda ()
(if (= 0 (modulo n 3))
(error n "is multiple of 3!"))
(1+ count))))))))))
Runs correctly:
1 ]=> 1,2,3,resuming...4,5,6,resuming...7,8,9,resuming...10,11,
;Value: 7

Two racket modules colliding

I am requiring two modules to my file:
(require sicp) ; contains set-car! and set-cdr!
(require (planet dyoo/sicp-concurrency:1:2/sicp-concurrency)) ; contains procedures parallel-execute and test-and-set!
Problem: both libraries use different flavors of scheme. The sicp-concurrency uses mzscheme. Requiring this module prevented me from using else in a cond clause.
Is there a way to prevent the features of mzscheme in sicp-concurrency while still making use of the procedures I needed?
I have updated Danny Yoo's code to Racket 7.
Get the new file "sicp-concurrency.rkt" here:
https://gist.github.com/soegaard/d32e12d89705c774b71ee78ef930a4bf
Save the file in the same folder as your program file.
Here is an example of use:
#lang sicp
(#%require "sicp-concurrency.rkt")
(define (test-1)
(define x 10)
(parallel-execute (lambda () (set! x (* x x)))
(lambda () (set! x (+ x 1))))
x)
(define (test-2)
(define x 10)
(define s (make-serializer))
(parallel-execute (s (lambda () (set! x (* x x))))
(s (lambda () (set! x (+ x 1)))))
x)
(test-1)
(test-1)
(test-1)
(test-1)
(test-1)

Custom Scheme indexing function returns list-external value

I'm a newbie to scheme programming and I was writing small codes when I encountered the following issue and couldn't reason about it satisfactorily.
(define (at_i lst i)
(if (eq? i 0)
(car lst)
(at_i (cdr lst)
(- i 1) )))
Evaluation of (at_i '(1 2 3 4) 0) returns 1.
Now lets define same procedure with a lambda syntax.
(define (at_i lst i)
(lambda (vec x)
(if (eq? x 0)
(car vec)
(at_i (cdr vec)
(- x 1) )))
lst i)
But now Evaluation of (at_i '(1 2 3 4) 0) returns 0, which is not in the list and in general, it returns element at index-1.
I don't understand why this is happening.
Note: I just realized its not returning element at index - 1 but the index itself. The reason for this has been well explained below by #Renzo. Thanks!
First, you should indent properly the code if you intend to learn the language, since code indentation is very important to understand programs in Scheme and Lisp-like languages.
For instance, your function correctly indented is:
(define (at_i lst i)
(lambda (vec x)
(if (eq? x 0)
(car vec)
(at_i (cdr vec) (- x 1))))
lst
i)
From this you can see that you are defining the function at_i exactly as before in terms of a function with two parameters (lst and i), and whose body is constitued by three expressions: the first lambda (vec x) ... (- x 1)))), which is an (anonymous) function (lambda) which is not called or applied, the second, which is the first parameter lst, and finally the third which is the second parameter i. So, when the function at_i is called with two arguments, the result is the evaluation of the three expressions in sequence, the first two values are discarded (the function and the value of lst), and the result is the value of the second parameter i. This is reason for which the result of (at_i '(1 2 3 4) 0) is 0, since it is the value of i.
A proper redefinition of the function in lambda form would be the following, for instance:
(define at_i
(lambda (vec x)
(if (eq? x 0)
(car vec)
(at_i (cdr vec) (- x 1)))))
(at_i '(1 2 3 4) 0) ;; => 1
in which you can see that the name at_i, through the define, is associated to a two parameter function which calculates correctly the result.
eq? is memory object equality. Only some Scheme implementations interpret (eq? 5 5) as #t. Use = for numbers, eqv? for values, and equal? for collections.
(define (index i xs) ; `index` is a partial function,
(if (= i 0) ; `i` may go out of range
(car xs)
(index (- i 1) ; Tail recursion
(cdr xs) )))
Your second function returns the index because you missed parenthesis around the lambda's application. It should be
(define (index i xs)
((lambda (i' xs')
(if (= i' 0)
(car xs')
(index (- i' 1) ; Not tail-recursive
(cdr xs') )))
i xs))
But this is verbose and differs semantically from the first formulation.
You say you are defining the "same procedure with a lambda syntax", but you are not. That would be (define at_i (lambda lst i) ...). Instead, you are effectively saying (define (at_i lst i) 1 2 3), and that is 3, of course.
In your particular case, you defined the procedure at_i to return (lambda (vec x) ...), lst and i. Now, if you call (at_i '(1 2 3 4) 0), the procedure will return 0, since that is the value of i at this point.

application: not a procedure racket

i am new to racket. i am trying create a list from the input of the user and when the value 0 is entred the first three elements are printed.
here is the code:
#lang racket
(define lst '())
(define (add)
(define n(read))
(if (= n 0)
;then
(
list (car lst) (cadr lst) (caddr lst)
)
;else
(
(set! lst (append lst (list n)))
(add)
)
)
)
(add)
i tested the program with the values 1 2 3 4 5 0
but i keep getting this error:
application: not a procedure;
expected a procedure that can be applied to arguments
given: #<void>
arguments...:
'(1 2 3)
can anyone help me figure out what's wrong.
If you have more than one expression in the "then" or "else" parts, you must enclose them inside a begin, because a pair of () in Scheme are used for function application - that explains the error you're getting. Try this:
(define (add)
(define n (read))
(if (= n 0)
; then
(list (car lst) (cadr lst) (caddr lst))
; else
(begin
(set! lst (append lst (list n)))
(add))))
I had a similar problem, in a function i called a parameter with the same name of a structure, so, trying to create an instance of that structure i got the same error.
example:
> (struct example (param1 param2) #:transparent)
> (define e (example 1 2))
> e
(example 1 2)
> (define (fn e)
(example (example-param1 e) 0))
> (fn e)
(example 1 0)
> (define (fn example)
(example (example-param1 example) 0))
> (fn e)
application: not a procedure;
expected a procedure that can be applied to arguments
given: (example 1 2)
arguments...:
I hope this helps
Your code have a few problems, for example it will fail if you enter less than 3 elements. Also, it is not considered good style to define variables at the module level.
I'd suggest the following:
(define (add)
(define (sub cnt lst)
(define n (read))
(if (= n 0)
(reverse lst)
(if (< cnt 3)
(sub (add1 cnt) (cons n lst))
(sub cnt lst))))
(sub 0 '()))

Assigning variables (variable mutation) in racket

I have the following function that given an expression, executes it :
(define (foo exp0) exp0)
If I do the following:
(define x 5)
(foo (+ x 4))
(foo (* x 2))
display(x)
I would like for display(x) to display 18. Basically, how can I assign the value of the given expression back to the given variable?
First, the foo procedure is simply returning the parameter, it's not "executing" it. Answering your question, here's how you can reassign a value in Scheme:
(define x 5)
(set! x (+ x 4))
(set! x (* x 2))
(display x)
But to tell the truth, that style of programming (mutating variables) is frowned upon in Scheme. I believe this is more idiomatic:
(let* ((x 5)
(y (+ x 4))
(z (* y 2)))
(display z))
You can indeed write such a macro, if you can guarantee that the variable you're updating is always the first operand:
(define-syntax foo
(syntax-rules ()
((foo (op var arg ...))
(set! var (op var arg ...)))))