0

My background is Javascript, Python & a bit of Haskell. Hi I am new to Scheme (1 day old). I want to understand the difference between below 2 code snippets.

(define onePlus (lambda (v) (+ 1 v)))
(onePlus 4) ; 5 

With CallCC

(define anotherOnePlus 0)
(+ 1 (call/cc (lambda (k) (set! anotherOnePlus k) (k 4)))) ; 5
(anotherOnePlus 4); 5

Why anyone want to do the 2nd way to get hold of the function you live in. What am I missing in a bigger picture?

Is there any limitations of Scope for getting hold of functions?

(define temp 0)
(+ 1 (+ 2 (+ 3 (call/cc (lambda (k) (set! temp k) (k 4)))))) ; 10
(temp 5) ; 11

Here it is definitely looks like h => 1 + 2 + 3 + h in JS. What if I want to get hold of on (+ 3 h) that means I need to write it in a separate line?

Pawan Kumar
  • 1,443
  • 2
  • 16
  • 30
  • 2
    If it's your day 1 with Scheme, you shouldn't start with continuations :) . They're not a "limitation" of scoping rules. Think of them as a way to have greater control over the execution stack, but you'll rarely need to use them in your day-to-day work. – Óscar López Dec 09 '19 at 09:09
  • 1
    Haskell only has *delimited* continuations. Scheme's *undelimited* continuations can save and re-enter *any* context. calling `(k val)` gotten from `.... (call/cc (lambda (k) ....)) ....` returns `val` into that context which awaited the return value of that `(call/cc (lambda (k) ....))` form. The only analog I know of is C's `longjmp`. [TSPL](https://www.scheme.com/tspl4/) has more. Also, other books on Scheme. – Will Ness Dec 10 '19 at 07:35
  • Thanks @WillNess for differentiating Haskell from Scheme, I was confused comparing Scheme from callCC in Haskell. I found this link very helpful https://blogs.msdn.microsoft.com/ashleyf/2010/02/11/turning-your-brain-inside-out-with-continuations/ – Pawan Kumar Dec 10 '19 at 16:48
  • 1
    take note though that the "continuations" in CPS are *not* Scheme's full, "real" undelimited continuations. the "continuations" in CPS are functions, but [undelimited continuations are not functions](http://okmij.org/ftp/continuations/undelimited.html). – Will Ness Dec 10 '19 at 16:52

1 Answers1

1

The only reason to do the 2nd if you are going to do the calculations over an over again with just different value. In practise it is a goto and if your continuations weren't delimited it is an infinite loop. eg. Try this:

(define anotherOnePlus 0)
(let ()
  (+ 1 (call/cc (lambda (k) (set! anotherOnePlus k) (k 4)))) ; 5
  (anotherOnePlus 4)); 5

You'll never get an answer since (anotherOnePlus 4) brings you back to (+ 1 4) with the continuation (anotherOnePlus 4) which brings you right back again.

There is no limitation of the function. As long as it is referenced it will not be garbage collected.

A better way to demonstrate call/cc would be with a better example. If you ever going to implement map with more than one list you need to fetch the cars unless one of the list is empty, then the result should be empty. You can do this by first iterating the whole list making sure there are no empty lists:

(define (cars-1 lsts)
  (define (have-elements? lsts)
    (cond ((null? lsts) #t)
          ((null? (car lsts)) #f)
          (else (have-elements? (cdr lsts)))))
  (define (cars lsts)
    (if (null? lsts)
        '()
        (cons (caar lsts)
              (cars (cdr lsts)))))
  (if (have-elements? lsts)
      (cars lsts)
      '()))

But there is a clever solution where you just do it an if you find an empty element you bail. This can be done with continuations like this:

(define (cars lsts)
  (define (cars lsts k)
    (cond ((null? lsts) (k '()))
          ((null? (car lsts)) '())
          (else (cars (cdr lsts)
                      (lambda (res)
                        (k (cons (caar lsts)
                              res)))))))
  (cars lsts values))

Now wouldn't it be great if we could let the language do the continuations and that we just chose if we used them or not? Scheme does that for you. You write it like this:

(define (cars lsts)
  (call/cc
   (lambda (bail)
     (define (cars lsts)
       (cond ((null? lsts) '())
             ((null? (car lsts)) (bail '()))
             (else (cons (caar lsts)
                         (cars (cdr lsts))))))
     (cars lsts))))

Now if you look at the reference implementation of SRFI-1 List library you'll see they actually do it this way.

Sylwester
  • 47,942
  • 4
  • 47
  • 79