Both of the following code blocks should (in my mind) be infinite loops
This works
(define call/cc call-with-current-continuation)
(define l 0)
(define i 0)
((lambda ()
(call/cc
(lambda (k)
(set! l k)))
(write i)
(newline)
(set! i (+ i 1))
(l "ignore")))
This does not work:
(define call/cc call-with-current-continuation)
(define l 0)
(define i 0)
(begin
(call/cc
(lambda (k)
(set! l k)))
(write i)
(newline)
(set! i (+ i 1))
(l "ignore"))
The only difference is one uses a lambda and one uses a begin block.
Why does the second block of code not work?
Thanks
In the second case, the begin splices its arguments into the top-level. Note that there are two kinds of begin: if it's in an expression position, it just sequences operations one after the other. The second kind (which is what you have) will splice all of its arguments into the surrounding context.
The spliced call/cc expression's continuation is actually the empty continuation, since each top-level expression is evaluated separately (i.e., in the empty continuation). You can check this by putting a let around the begin, which forces it to be in an expression position. Then it will infinite loop like you expect.
Related
This function is displaying the correct thing, but how do I make the output of this function another function?
;;generate an Caesar Cipher single word encoders
;;INPUT:a number "n"
;;OUTPUT:a function, whose input=a word, output=encoded word
(define encode-n
(lambda (n);;"n" is the distance, eg. n=3: a->d,b->e,...z->c
(lambda (w);;"w" is the word to be encoded
(if (not (equal? (car w) '()))
(display (vtc (modulo (+ (ctv (car w)) n) 26)) ))
(if (not (equal? (cdr w) '()))
((encode-n n)(cdr w)) )
)))
You're already returning a function as output:
(define encode-n
(lambda (n)
(lambda (w) ; <- here, you're returning a function!
(if (not (equal? (car w) '()))
(display (vtc (modulo (+ (ctv (car w)) n) 26))))
(if (not (equal? (cdr w) '()))
((encode-n n)(cdr w))))))
Perhaps a simpler example will make things clearer. Let's define a procedure called adder that returns a function that adds a number n to whatever argument x is passed:
(define adder
(lambda (n)
(lambda (x)
(+ n x))))
The function adder receives a single parameter called n and returns a new lambda (an anonymous function), for example:
(define add-10 (adder 10))
In the above code we created a function called add-10 that, using adder, returns a new function which I named add-10, which in turn will add 10 to its parameter:
(add-10 32)
=> 42
We can obtain the same result without explicitly naming the returned function:
((adder 10) 32)
=> 42
There are other equivalent ways to write adder, maybe this syntax will be easier to understand:
(define (adder n)
(lambda (x)
(+ n x)))
Some interpreters allow an even shorter syntax that does exactly the same thing:
(define ((adder n) x)
(+ n x))
I just demonstrated examples of currying and partial application - two related but different concepts, make sure you understand them and don't let the syntax confound you.
(define wadd (lambda (i L)
(if (null? L) 0
(+ i (car L)))
(set! i (+ i (car L)))
(set! L (cdr L))))
(wadd 9 '(1 2 3))
This returns nothing. I expect it to do (3 + (2 + (9 + 1)), which should equate to 15. Am I using set! the wrong way? Can I not call set! within an if condition?
I infer from your code that you intended to somehow traverse the list, but there's nothing in the wadd procedure that iterates over the list - no recursive call, no looping instruction, nothing: just a misused conditional and a couple of set!s that only get executed once. I won't try to fix the procedure in the question, is beyond repair - I'd rather show you the correct way to solve the problem. You want something along these lines:
(define wadd
(lambda (i L)
(let loop ((L L)
(acc i))
(if (null? L)
acc
(loop (cdr L) (+ (car L) acc))))))
When executed, the previous procedure will evaluate this expression: (wadd 9 '(1 2 3)) like this:
(+ 3 (+ 2 (+ 1 9))). Notice that, as pointed by #Maxwell, the above operation can be expressed more concisely using foldl:
(define wadd
(lambda (i L)
(foldl + i L)))
As a general rule, in Scheme you won't use assignments (the set! instruction) as frequently as you would in an imperative, C-like language - a functional-programming style is preferred, which relies heavily on recursion and operations that don't mutate state.
I think that if you fix your indentation, your problems will become more obvious.
The function set! returns <#void> (or something of similar nothingness). Your lambda wadd does the following things:
Check if L is null, and either evaluate to 0 or i + (car L), and then throw away the result.
Modify i and evaluate to nothing
Modify L and return nothing
If you put multiple statements in a lambda, they are wrapped in a begin statement explicitly:
(lambda () 1 2 3) => (lambda () (begin 1 2 3))
In a begin statement of multiple expressions in a sequence, the entire begin evaluates to the last statement's result:
(begin 1 2 3) => 3
In the expression (call/cc (lambda (k) (k 12))), there are three continuations: (k 12), (lambda (k) (k 12)), and (call/cc (lambda (k) (k 12))). Which one is the "current continuation"?
And continuations in some books are viewed as a procedure which is waiting for a value and it will return immediately when it's applied to a value. Is that right?
Can anyone explain what current continuations are in detail?
Things like (k 12) are not continuations. There is a continuation associated with each subexpression in some larger program. So for example, the continuation of x in (* 3 (+ x 42)) is (lambda (_) (* 3 (+ _ 42))).
In your example, the "current continuation" of (call/cc (lambda (k) (k 12))) would be whatever is surrounding that expression. If you just typed it into a scheme prompt, there is nothing surrounding it, so the "current continuation" is simply (lambda (_) _). If you typed something like (* 3 (+ (call/cc (lambda (k) (k 12))) 42)), then the continuation is (lambda (_) (* 3 (+ _ 42))).
Note that the lambdas I used to represent the "current continuation" are not the same as what call/cc passes in (named k in your example). k has a special control effect of aborting the rest of the computation after evaluating the current continuation.
The continuation in this case is the "thing" that receives the return value of the call/cc invocation. Thus:
(display (call/cc (lambda (k) (k 12)))
has the same result as
(display 12)
Continuations in Scheme "look and feel" like procedures, but they do not actually behave like procedures. One thing that can help you understand continuations better is CPS transformations.
In CPS transformation, instead of a function returning a value, instead it takes a continuation parameter, and invokes the continuation with the result. So, a CPS-transformed sqrt function would be invoked with (sqrt 64 k) and rather than returning 8, it just invokes (k 8) in tail position.
Because continuations (in a CPS-transformed function) are tail-called, the function doesn't have to worry about the continuation returning, and in fact, in most cases, they are not expected to return.
With this in mind, here's a simple example of a function:
(define (hypot x y)
(sqrt (+ (* x x) (* y y))))
and its CPS-transformed version:
(define (hypot x y k)
(* x x (lambda (x2)
(* y y (lambda (y2)
(+ x2 y2 (lambda (sum)
(sqrt sum k))))))))
(assuming that *, +, and sqrt have all been CPS-transformed also, to accept a continuation argument).
So now, the interesting part: a CPS-transformed call/cc has the following definition:
(define (call/cc fn k)
(fn k k))
With CPS transformation, call/cc is easy to understand and easy to implement. Without CPS transformation, call/cc is likely to require a highly magical implementation (e.g., via stack copying, etc.).
(let ([x (call/cc (lambda (k) k))])
(x (lambda (ignore) "hi"))) => "hi"
How can I write the executing steps of this continuation?
The call/cc operator is used to call a given procedure with the current continuation (hence the name call-with-current-continuation). So to understand how it works, we need to know what the current continuation is.
In your program, at the point that the call/cc is executed, the continuation looks like this:
CONT = (let ([x HOLE])
(x (lambda (ignore) "hi")))
where HOLE is a placeholder for a value to plug in. In other words, the continuation is the remaining computation. You can stick a value into the continuation if you want to progress.
Now, call/cc captures this continuation and passes it to the procedure (lambda (k) k). You can see that this procedure just immediately returns the continuation. So the program reduces to:
(let ([x CONT])
(x (lambda (ignore) "hi")))
Applying a continuation captured by call/cc replaces the current computation with that continuation plugged with the value you give it. So the application (x (lambda (ignore) "hi")) turns into:
(let ([x (lambda (ignore) "hi")])
(x (lambda (ignore) "hi")))
and the rest should follow from what you already know about lambdas and application.
In the first line [x (call/cc (lambda (k) k))] we're creating a new continuation which is bound to the k parameter in the received lambda. That k is returned and in turn bound to the x local variable - therefore, x is a continuation.
In the second line, x is called with a single-argument lambda; the argument is ignored and the result of invoking (lambda (ignore) "hi") is "hi", which is finally returned as the result of the continuation. This is equivalent to simply calling:
(call/cc
(lambda (k)
(k "hi")))
Why does this expression evaluate to "hi" ?
(let ([x (call/cc (lambda (k) k))])
(x (lambda (ignore) "hi")))
The first step is to decide what k looks like:
(define k
(lambda (value)
(let ((x value))
(x (lambda (ignore) "hi")))))
We see immediately that this is the same as
(define k
(lambda (x)
(x (lambda (ignore) "hi"))))
But, I failed to mention one little detail. If k is
ever invoked, it is as if it were invoked in tail position.
So (f (k 3)) for all continuations k built by call/cc is the
same as (k 3). That is always a little bit tricky.
So, let's use lambda^ to mean that the function it introduces
is to be invoked as if it were in tail position.
(define k
(lambda^ (x)
(x (lambda (ignore) "hi"))))
Now we know what k is, we also need to know that returning
out of (call/cc (lambda (k) k)) is really using a default.
It should have been written correctly as
(call/cc (lambda (k) (k k))).
There is always an implied invocation of k at the top of the
body of the lambda expression passed to call/cc.
We know what k is.
So, we know that this must be the same as, (for ease of reading let's
turn the x's in the argument position into y's.)
((lambda^ (x) (x (lambda (ignore) "hi")))
(lambda^ (y) (y (lambda (ignore) "hi"))))
So, we evaluate both positions to functions.
Once we invoke the function in function position,
we are done, since it is headed by lambda^ So, we need to know that
((lambda^ (x) (x (lambda (ignore) "hi")))
(lambda^ (y) (y (lambda (ignore) "hi"))))
evaluates to, substituting for x
((lambda^ (y) (y (lambda (ignore) "hi")))
(lambda (ignore) "hi"))
and one more step, substituting for y
leads to
((lambda (ignore) "hi") (lambda (ignore) "hi")), which ignores
its argument and returns "hi"
The following example involves jumping into continuation and exiting out. Can somebody explain the flow of the function. I am moving in a circle around continuation, and do not know the entry and exit points of the function.
(define (prod-iterator lst)
(letrec ((return-result empty)
(resume-visit (lambda (dummy) (process-list lst 1)))
(process-list
(lambda (lst p)
(if (empty? lst)
(begin
(set! resume-visit (lambda (dummy) 0))
(return-result p))
(if (= 0 (first lst))
(begin
(call/cc ; Want to continue here after delivering result
(lambda (k)
(set! resume-visit k)
(return-result p)))
(process-list (rest lst) 1))
(process-list (rest lst) (* p (first lst))))))))
(lambda ()
(call/cc
(lambda (k)
(set! return-result k)
(resume-visit 'dummy))))))
(define iter (prod-iterator '(1 2 3 0 4 5 6 0 7 0 0 8 9)))
(iter) ; 6
(iter) ; 120
(iter) ; 7
(iter) ; 1
(iter) ; 72
(iter) ; 0
(iter) ; 0
Thanks.
The procedure iterates over a list, multiplying non-zero members and returning a result each time a zero is found. Resume-visit stores the continuation for processing the rest of the list, and return-result has the continuation of the call-site of the iterator. In the beginning, resume-visit is defined to process the entire list. Each time a zero is found, a continuation is captured, which when invoked executes (process-list (rest lst) 1) for whatever value lst had at the time. When the list is exhausted, resume-visit is set to a dummy procedure. Moreover, every time the program calls iter, it executes the following:
(call/cc
(lambda (k)
(set! return-result k)
(resume-visit 'dummy)))
That is, it captures the continuation of the caller, invoking it returns a value to the caller. The continuation is stored and the program jumps to process the rest of the list.
When the procedure calls resume-visit, the loop is entered, when return-result is called, the loop is exited.
If we want to examine process-list in more detail, let's assume the list is non-empty. Tho procedure employs basic recursion, accumulating a result until a zero is found. At that point, p is the accumulated value and lst is the list containing the zero. When we have a construction like (begin (call/cc (lambda (k) first)) rest), we first execute first expressions with k bound to a continuation. It is a procedure that when invoked, executes rest expressions. In this case, that continuation is stored and another continuation is invoked, which returns the accumulated result p to the caller of iter. That continuation will be invoked the next time iter is called, then the loop continues with the rest of the list. That is the point with the continuations, everything else is basic recursion.
What you need to keep in mind is that, a call to (call/cc f) will apply the function f passed as argument to call/cc to the current continuation. If that continuation is called with some argument a inside the function f, the execution will go to the corresponding call to call/cc, and the argument a will be returned as the return value of that call/cc.
Your program stores the continuation of "calling call/cc in iter" in the variable return-result, and begins processing the list. It multiplies the first 3 non-zero elements of the list before encountering the first 0. When it sees the 0, the continuation "processing the list element 0" is stored in resume-visit, and the value p is returned to the continuation return-result by calling (return-result p). This call will make the execution go back to the call/cc in iter, and that call/cc returns the passed value of p. So you see the first output 6.
The rest calls to iter are similar and will make the execution go back and forth between such two continuations. Manual analysis may be a little brain-twisting, you have to know what the execution context is when a continuation is restored.
You could achieve the same this way:
(define (prod-iter lst) (fold * 1 (remove zero? lst)))
... even though it could perform better by traversing only once.
For continuations, recall (pun intended) that all call/cc does is wait for "k" to be applied this way:
(call/cc (lambda (k) (k 'return-value)))
=> return-value
The trick here is that you can let call/cc return its own continuation so that it can be applied elsewhere after call/cc has returned like this:
;; returns twice; once to get bound to k, the other to return blah
(let ([k (call/cc (lambda (k) k))]) ;; k gets bound to a continuation
(k 'blah)) ;; k returns here
=> blah
This lets a continuation return more than once by saving it in a variable. Continuations simply return the value they are applied to.
Closures are functions that carry their environment variables along with them before arguments get bounded to them. They are ordinary lambdas.
Continuation-passing style is a way to pass closures as arguments to be applied later. We say that these closure arguments are continuations. Here's half of the current code from my sudoku generator/solver as an example demonstrating how continuation-passing style can simplify your algorithms:
#| the grid is internally represented as a vector of 81 numbers
example: (make-vector 81 0)
this builds a list of indexes |#
(define (cell n) (list (+ (* (car 9) (cadr n))))
(define (row n) (iota 9 (* n 9)))
(define (column n) (iota 9 n 9))
(define (region n)
(let* ([end (+ (* (floor-quotient n 3) 27)
(* (remainder n 3) 3))]
[i (+ end 21)])
(do ([i i
(- i (if (zero? (remainder i 3)) 7 1))]
[ls '() (cons (vector-ref *grid* i) ls)])
((= i end) ls))))
#| f is the continuation
usage examples:
(grid-ref *grid* row 0)
(grid-set! *grid* region 7) |#
(define (grid-ref g f n)
(map (lambda (i) (vector-ref g i)) (f n)))
(define (grid-set! g f n ls)
(for-each (lambda (i x) (vector-set! g i x))
(f n) ls))