2

So for I am trying to figure out this whole call/cc thing in Scheme. Below is the code I am working with:

(+ 1 (call/cc
  (lambda (k)
    (if (number? k)
        (call/cc (lambda (k) (k (- 1 k))))
        (k 4)))))

So here we start adding the two arguments in the first parenthesis. 1 and the rest which we have to evaluate because of eager evaluation. So we have a call/cc which accepts one arguments, a function, which the call/cc evaluates by calling. (am I right?) And at the same time it holds the rest of what has happened so far in our first parenthesis, namely (+ 1 []), which is the "continuation". (am I right?) So we call lambda k with the continuation as I have just described, (+ 1 []). In the function it then asks if this is a number, which it is not and does the "then". I get "lost" here, what does this second call/cc do? What is (k 4) invoked, to make this whole thing evaluate to 5?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • Avoid shadowing your inner scope prefer rename your argument of the second call/cc. Do you mean `(call/cc (lambda (e) (e (- 1 e))))` or `(call/cc (lambda (e) (e (- 1 k))))` in any case it wont be evaluate and it is wrong if you wouldn't have the if statement. – mathk Jul 25 '12 at 15:28

2 Answers2

4

You're pretty close! All of your questions are right, I think.

The function you pass to call/cc takes one argument (k in your example), and it's a way to return a value to the current continuation. k is a function of one argument. When you call that function with a value, that value is returned to and stands in place of the _ in this: (+ 1 _).

So in your example, (number? k) is never true, and the second call to call/cc is never executed. (Even if it were, it would fail with a runtime error where (- 1 k) subtracts a function from 1.) So it actually executes the "else" branch: (k 4), which returns 4 to (+ 1 4) so the result is 5.

Hope that's clear!

okonomichiyaki
  • 8,355
  • 39
  • 51
  • Before I say anything, so this means in C++ terms, "calling" call/cc means calling another function, but I am just writing the function as the argument to the call/cc call. Second question, if the function as the argument of the call/cc call has one argument, or many, how do I define what I am passing to them? This question arises because, in my example what exactly am I passing as a argument to the function that is the argument of the call/cc call? Not a number, so it is a continuation "(+ 1 _)" as you explained; in this case. –  Jul 25 '12 at 03:07
  • ***** second question if the funtion *of the –  Jul 25 '12 at 03:08
  • This means that whatever I call in my call to call/cc means I can only return a definite value or I would wait forever? ... Also what does (k 4) means exactly? how does it read? "I assign k to 4?" which I know is wrong but that is how it looks to me. –  Jul 25 '12 at 03:10
  • Ok so if I wanted to call the display statement what should I change (number?) to?(+ 1 (call/cc (lambda (k) (if (number? k) (display "never") (k 4))))) –  Jul 25 '12 at 03:52
  • I don't really know C++ so I can't really comment on that. But `call/cc` is a built-in function that takes one argument, and that argument has to be a function that takes a single argument, which is a function of a single argument. If that's very confusing to you, you might want to start with some simpler examples of higher-order functions than `call/cc` because it's a pretty mind-bending feature. – okonomichiyaki Jul 25 '12 at 04:20
  • `(k 4)` is a function application. Here `k` is a variable, and the value it holds is a function. 4 is the argument to that function. In C++, this would look like `k(4)`. – okonomichiyaki Jul 25 '12 at 04:21
  • If you just want to print something out you could just change your code to this: `(+ 1 (call/cc (lambda (k) (display "hi! from inside (lambda (k) ...)") (k 4))))` – okonomichiyaki Jul 25 '12 at 04:23
  • So where is k defined? Why does it just return its arguments? Is k the arguments to the call/cc call? If so does this not introduce a infinite loop printing "hi ..."? because calling (k 4) would call the function again printing "hi" then calling again with 4 .... etc. Why does it stop? –  Jul 25 '12 at 15:10
  • `k` is the formal parameter of the function passed to `call/cc` (defined by `lambda`). I suggest you spend some more time with the simpler parts of Scheme before tackling `call/cc`. – okonomichiyaki Jul 25 '12 at 15:41
  • So k is not a function but a formal parameter. If it is not a function why does (k 4) do anything? What exactly does the "(k 4)" do? .... ligthbulb. (k 4) passes 4 to k which is the continuation.... so that is why we get 5 for the evaluation of it all. so (k 4) is basically saying return 4 to the spot where call/cc was called? –  Jul 25 '12 at 16:00
  • `k` is the formal parameter of that anonymous function, and when that anonymous function is called, the actual parameter will be a function of one argument. So `k` will be a function, that is applied like `(k 4)`. As I said, you might want to play with simpler examples of higher order functions (like map, fold, and filter) if this stuff is confusing. – okonomichiyaki Jul 25 '12 at 16:25
  • I know I am inches to understanding it fully. I am trying to focus on this now because this is what we are doing in class. We are converting from quarters to semesters, so this programming course is three weeks long. I just was introduced to scheme 5 days ago.... So I am doing my best. thank you for your help! –  Jul 25 '12 at 17:54
1

call/cc is like setjmp. It defines an exit point that the later code can directly "jump" to, like longjmp does.

It follows a certain protocol for that, so we always write

( .... surrounding code .....
   (call/cc (lambda (k)
      .... inner code which has access to the exit point "k" ....
      )) .... more surrounding code .... )

Under that protocol, the "inner" code executes as usual, but it also has a name, k, in its scope. None of the "surrounding" code has access to it, since it's out of k's scope.

k here is a first-class value (naturally, as it is named). The Scheme run-time system will assign it a continuation of the (call/cc ...) call point, automatically, behind the scenes. For a programmer, we can use it whenever we have access to it.

A continuation is a function of one argument. When that function is called, it will pass its argument on to the continuation's calling context. But since k is a first-class named value, we can pass it around freely. The "inner" code can be as complex as we want, it can call out into other functions defined elsewhere etc. If it passes k as an argument to such external function, it can use it just as well.

Calling k with a value means returning that value into the calling context of the original (call/cc ...) call. Directly. Just like longjmping there (except we can return any value there, not just int).

Will Ness
  • 70,110
  • 9
  • 98
  • 181