This code works as expected:
(define saved #f)
(cons 'wo (call/cc (lambda (k) (set! saved k) '())))
(saved 'ca!)
output (Racket console):
'(wo)
'(wo . ca!)
But when I wrap it in a function and call it, the program never stops. Why?
(define (test)
(define saved #f)
(cons 'wo (call/cc (lambda (k) (set! saved k) '())))
(saved 'ca!))
(test)
A continuation is all that's left to be done in the execution context where it's saved.
In the first case, the continuation is saved when calling cons, so it's just to cons 'wo to something and return to the REPL.
In the second case, you call procedure test, so the continuation is both
cons 'wo to something
call the procedure bound to saved (i.e. the continuation) with 'ca!
so the continuation calls itself, hence the loop.
Related
I am new to Scheme programming and have been trying to understand the control flow of the programs having call-with-current-continuation in them. To be more specific, I want to know when the call to any continuation is invoked where is the control transferred and what happens after that. It would be really helpful if the below mentioned program is considered for the explanation.
(define call/cc call-with-current-continuation)
(define amb-exit '())
(define amb
(lambda ()
(call/cc
(lambda (m)
(call/cc
(lambda (f1)
(set! amb-exit (lambda () (f1 'exit)))
(m 1)))
(call/cc
(lambda (f2)
(set! amb-exit (lambda () (f2 'exit)))
(m 2)))
(call/cc
(lambda (f3)
(set! amb-exit (lambda () (f3 'exit)))
(m 3)))))))
(define back (lambda () (amb-exit)))
Now, I try to run the code this way (define a (amb)) and then I get the value in the terminal like this ;Value: a. Then in the terminal I check the value of a which returns me ;Value: 1. Then I call (back) I get a with the new value ;Value: 2. So on...
I know that when I do (define a (amb) the continuation f1 is invoked in the statement (set! amb-exit (lambda () (f1 'exit))) which transfers the control back to the first inner call/cc and the f1 continuation returns exit.
The thing that I am not able to understand is why the ;Value: a is ;Value: 1 instead of the value exit which is returned by f1?
The moment this part (f1 'exit) is executed, control returns back to first inner call/cc abandoning whatever (in this case (m 1)) after it.
So, this part (m 1) should never be invoked because the first inner continuation i.e. f1 is returned with exit even before hitting (m 1).
Any helpful comments regarding call-with-current-continuation in Scheme would also be appreciated.
Note: Using MIT/GNU Scheme
No, when you do (define a (amb)) the continuation f1 is not invoked, because it is behind (i.e. inside) a lambda.
No, (set! amb-exit (lambda () (f1 'exit))) sets amb-exit to the lambda function, and then the control passes to (m 1) which does invoke the continuation m. Which returns 1 from (amb) in (define a (amb)), which thus sets a to 1.
When you later call (back) it calls (amb-exit) which at that point invokes the f1 continuation with (f1 'exit) which returns the value 'exit from the (call/cc (lambda (f1) ...)) form. This value is discarded, and control passes into the (call/cc (lambda (f2) ...)) form, with similar effects.
This code works as expected:
(define saved #f)
(cons 'wo (call/cc (lambda (k) (set! saved k) '())))
(saved 'ca!)
output (Racket console):
'(wo)
'(wo . ca!)
But when I wrap it in a function and call it, the program never stops. Why?
(define (test)
(define saved #f)
(cons 'wo (call/cc (lambda (k) (set! saved k) '())))
(saved 'ca!))
(test)
A continuation is all that's left to be done in the execution context where it's saved.
In the first case, the continuation is saved when calling cons, so it's just to cons 'wo to something and return to the REPL.
In the second case, you call procedure test, so the continuation is both
cons 'wo to something
call the procedure bound to saved (i.e. the continuation) with 'ca!
so the continuation calls itself, hence the loop.
I don't understand why if I write
(define (iter-list lst)
(let ((cur lst))
(lambda ()
(if (null? cur)
'<<end>>
(let ((v (car cur)))
(set! cur (cdr cur))
v)))))
(define il2 (iter-list '(1 2)))
and call (il2) 2 times I have printed: 1 then 2
(that's the result I want to have)
But if I don't put (lambda () and apply (il2) 2times I obtain then 1
In other words why associating the if part to a function lambda() makes it keep the memory of what we did when we applied the function before?
This is what's happening. First, it's important that you understand that when you write this:
(define (iter-list lst)
(let ((cur lst))
(lambda ()
...)))
It gets transformed to this equivalent form:
(define iter-list
(lambda (lst)
(let ((cur lst))
(lambda ()
...))))
So you see, another lambda was there in the first place. Now, the outermost lambda will define a local variable, cur which will "remember" the value of the list and then will return the innermost lambda as a result, and the innermost lambda "captures", "encloses" the cur variable defined above inside a closure. In other words: iter-list is a function that returns a function as a result, but before doing so it will "remember" the cur value. That's why you call it like this:
(define il2 (iter-list '(1 2))) ; iter-list returns a function
(il2) ; here we're calling the returned function
Compare it with what happens here:
(define (iter-list lst)
(let ((cur lst))
...))
The above is equivalent to this:
(define iter-list
(lambda (lst)
(let ((cur lst))
...)))
In the above, iter-list is just a function, that will return a value when called (not another function, like before!), this function doesn't "remember" anything and returns at once after being called. To summarize: the first example creates a closure and remembers values because it's returning a function, whereas the second example just returns a number, and gets called like this:
(define il2 (iter-list '(1 2))) ; iter-list returns a number
(il2) ; this won't work: il2 is just a number!
il2 ; this works, and returns 1
When you wrap the if in a lambda (and return it like that), the cur let (which is in scope for the if) is attached to the lambda. This is called a closure.
Now, if you read a little bit about closures, you'll see that they can be used to hold onto state (just like you do here). This can be very useful for creating ever incrementing counters, or object systems (a closure can be used as a kind of inside out object).
Note that in your original code, you renamed lst as cur. You didn't actually need to do that. The inner lambda (the closure to be) could have directly captured the lst argument. Thus, this would produce the same result:
(define (iter-list lst)
(lambda ()
...)) ; your code, replace 'cur' with 'lst'
Here are some example of other closure-producing functions that capture a variable:
(define (always n)
(lambda () n))
(define (n-adder n)
(lambda (m) (+ n m)))
(define (count-from n)
(lambda ()
(let ((result n))
(set! n (+ n 1))
result)))
I'm having some difficulty understanding how for loops work in scheme. In particular this code runs but I don't know why
(define (bubblesort alist)
;; this is straightforward
(define (swap-pass alist)
(if (eq? (length alist) 1)
alist
(let ((fst (car alist)) (scnd (cadr alist)) (rest (cddr alist)))
(if (> fst scnd)
(cons scnd (swap-pass (cons fst rest)))
(cons fst (swap-pass (cons scnd rest)))))))
; this is mysterious--what does the 'for' in the next line do?
(let for ((times (length alist))
(val alist))
(if (> times 1)
(for (- times 1) (swap-pass val))
(swap-pass val))))
I can't figure out what the (let for (( is supposed to do here, and the for expression in the second to last line is also a bit off putting--I've had the interpreter complain that for only takes a single argument, but here it appears to take two.
Any thoughts on what's going on here?
That's not a for loop, that's a named let. What it does is create a function called for, then call that; the "looping" behavior is caused by recursion in the function. Calling the function loop is more idiomatic, btw. E.g.
(let loop ((times 10))
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))
gets expanded to something like
(letrec ((loop (lambda (times)
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))))
(loop 10))
This isn't actually using a for language feature but just using a variation of let that allows you to easily write recursive functions. See this documentation on let (it's the second form on there).
What's going on is that this let form binds the name it's passed (in this case for) to a procedure with the given argument list (times and val) and calls it with the initial values. Uses of the bound name in the body are recursive calls.
Bottom line: the for isn't significant here. It's just a name. You could rename it to foo and it would still work. Racket does have actual for loops that you can read about here.
i'm learning sicp now and do the ex2.23
i have wrirten the following code:
(define (for-each proc items)
(if (null? items)
#t
((proc (car items))
(for-each proc (cdr items)))))
but when running, cause error: procedure application: expected procedure, given: #; arguments were: ()
i think i know the reason: I call the for-each function recursively, every called for-each wanted to return value
but when i have modified the code:
(define (for-each proc items)
(cond ((null? items) #t)
(else (proc (car items)) (for-each proc (cdr items)))))
it runs well. I don't understand, why? in cond, does every called for-each no need to return value?
i used DrScheme, and choose language SICP
i'm not a native speaker of english, so if there is sth which isn't described clearly, pls tell me
but when running, cause error: procedure application: expected > procedure, given: #; arguments were: ()
i think i know the reason: I call the for-each function recursively, > every called for-each wanted to return value
No, it is because in the alternative clause of if you have the combination ((proc (car items)) (for-each proc (cdr items))). You intended to evaluate the two combinations (proc (car items)) and (for-each proc (cdr items)) sequentially, and to that end you thought putting them in another pair of parentheses would work. But in actuality, what you have specified is that the result of (proc (car items)) is a procedure to be applied to the argument which is the return value of (for-each proc (cdr items)). This is not the case, and you get an error. The key point being that parentheses in Lisp are not for grouping, but have a definite significance.
The problem is that if can only have a single combination in that position, whereas you want to have two in a row. On the other hand, cond does not suffer such a restriction; you can put as long a sequence of individual combinations in the consequent part of a cond clause as your heart desires. This state of affairs is simply how the language is defined to work.
You can just as well use cond in these situations, but if you still want to use if there are some options for stuffing multiple combinations into one. E. g. you can create a lambda procedure whose body is the two combinations and immediately fire it off:
(define (for-each proc items)
(if (null? items)
#t
((lambda ()
(proc (car items))
(for-each proc (cdr items)) )) ))
Or you can use begin which is actually meant to be used for such a purpose:
(define (for-each proc items)
(if (null? items)
#t
(begin
(proc (car items))
(for-each proc (cdr items)) ) ))