Search code examples
racket

Why is there an error about redefining a constant in code that doesn't redefine a constant?


The following code:

#lang racket

(define foo1234
  (call/cc
   (lambda (j) (j (lambda (_) (j 5))))))

(foo1234 (lambda (_) 2))

Produces an error about redefining a constant:

define-values: assignment disallowed;
 cannot re-define a constant
  constant: foo1234
  in module:"/Users/mheiber/one.rkt"

But I'm not redefining a constant!

What is the error message trying to telling me?


Solution

  • But you are, through the continuation!

    It might be clearer to take a look at the following program:

    #lang racket
    
    (define cont
      (let ([k* (call/cc (λ (k) k))])
        (println (list 'hello k*))
        k*))
    
    (println 'world)
    
    (cont 1)
    

    The above program results in:

    '(hello #<procedure>)
    'world
    '(hello 1)
    define-values: assignment disallowed;
     cannot re-define a constant
      constant: cont
      in module:'anonymous-module
    

    assuming that you have "Enforce constant definitions" ticked in the language setting of DrRacket (which is the default IIUC).

    Why? When call/cc is executed, we capture the continuation, which is:

    (define cont
      (let ([k* <hole>])
        (println (list 'hello k*))
        k*))
    

    and binds the continuation to k*. Then, we print the first "hello". We then bind the same continuation to cont.

    Next, we print "world".

    Then, we invoke the continuation with 1, so we are executing

    (define cont
      (let ([k* 1])
        (println (list 'hello k*))
        k*))
    

    and this is when the second "hello" is printed. Then, we redefine cont, which is when the error occurs.

    Note that it is possible to avoid the error by unticking "Enforce constant definitions" in the language setting of DrRacket. But yes, you do redefine the variable.