user3597931
user3597931

Reputation:

How to explain funny behavior of call/cc in Racket?

combine must map reduce a list with the binary operator bin but must return exc if it finds any value that fails the predicate pred?, and if it finds any such value it must not perform any calculation on the list.

This is a simple continuation problem.

#lang racket

(define (id x)
  x)

(define (const x)
  (lambda (_) x))

(define (combine pred? bin zero exc)
  (call/cc
   (lambda (exit)
     (letrec
         ((f (lambda (xs)
               (if (empty? xs)
                   zero
                   (if (pred? (first xs))
                       (exit exc)
                       (bin (first xs) (f (rest xs))))))))
       f))))

(define product
  (combine zero?
           *
           1
           0))

(product '(1 2 3 0 4))

The code almost works, but it has a very subtle error.

It raises the following exception:

define-values: assignment disallowed;
 cannot re-define a constant
  constant: product

It is easy to make it work. Only a small change is needed:

(define (combine pred? bin un zero exc)
  (lambda (ys)
    (call/cc
     (lambda (exit)
       (letrec
           ((f (lambda (xs)
                 (if (empty? xs)
                     zero
                     (if (pred? (first xs))
                         (exit exc)
                         (bin (first xs) (f (rest xs))))))))
         (f ys))))))

I see that the problem is that Racket the continuation of define is to define a function, but can anyone give more details? What syntatic transformations involved, for example?

Upvotes: 0

Views: 166

Answers (1)

Sylwester
Sylwester

Reputation: 48765

Think of the order you have to have here:

(define product (combine ....))

Here you first evaluate (combine ...) and the continuation is the rest of the program starting with storing the computed value as the name product. Calling the continuation from withing f jumps right back to storing product all over again.

By calling (product '(1 2 3 0 4)) you are redefining product since it is the continuation of the program and call/cc captures the continuation.

In your second attempt you do a true refactoring of wrapping it in a lambda and call f with the same argument. It's just delaying when the call/cc happens and thus what is included in the continuation. In this version the continuation is whatever comes after the (product ...) and not the setting pf product in (define product ...)

Upvotes: 1

Related Questions