Why do continuations not have useful arity? - scheme

Consider the following code:
(call-with-values
(lambda ()
(call/cc (lambda (k)
(k k k))))
(lambda (x y)
(procedure-arity y)))
It's pretty obvious here that the continuation at the point of the call/cc call is the lambda on the right-hand side, so its arity should be 2. However, the return value of the above (in Racket) is (arity-at-least 0) instead.
Indeed, running similar code in Guile (substituting procedure-minimum-arity for procedure-arity) shows that the continuation also supposedly allows any number of arguments, even though it's pretty clearly not the case.
So, why is that? As far as I understand (correct me if my understanding is wrong), the arity of a continuation is pretty straightforward: it's 1 except in the context of call-with-values, in which case it's whatever the arity of the right-hand-side lambda is. (Which, granted, can be complicated if it's a case-lambda or the like, but no more complicated than if you were calling (procedure-arity (case-lambda ...)) directly.)

A simpler way to see the same is:
(call-with-values
(lambda () (error 'arity "~v" (procedure-arity (call/cc (λ (k) k)))))
(lambda (x y) (procedure-arity y)))
and even simpler:
(procedure-arity (call/cc (λ (x) x)))
And for your question -- it's clear in the first case that the continuation expects two inputs, but cases like that are not too common. Eg, they're usually such examples, whereas "real code" would use define-values or have some unknown continuation, where the continuations that call/cc creates can have different arities depending on the context that they were created at. This means that there's not much point in trying to figure out these rare cases where the continuation's arity is known.
Footnote:
;; nonsensical, but shows the point
(define (foo) (call/cc (λ (x) x)))
(define x (foo))
(define-values [y z] (foo))

Related

Can someone explain equality to me in scheme/racket?

So I stumbled across this today and it has me puzzled.
(define (x) '(1))
(eq? (x) (x)) ;=> #t
(eq? '(1) '(1)) ;=> #f
(define (y) (list 1))
(eq? (y) (y)) ;=> #f
(eq? (list 1) (list 1)) ;=> #f
Can anyone explain what's happening here ?
When compiled this program
(define (x) '(1))
(eq? (x) (x))
(eq? '(1) '(1))
is compiled into (something like):
(define datum1 '(1))
(define datum2 '(1))
(define datum3 '(1))
(define (x) datum1)
(eq? (x) (x))
(eq? datum2 datum3)
Therefore (x) will always return the object stored in datum1.
The expressions (eq? '(1) '(1)) on the other hand will
find out that datum2 and datum3 does not store the same object.
Note: There is a choice for the compiler writer. Many Scheme implementation will compile the above program to:
(define datum1 '(1))
(define (x) datum1)
(eq? (x) (x))
(eq? datum1 datum1)
and then the result will be true in both cases.
Note: The documentation of quote doesn't explicitly state whether multiple occurrences of '(1) in a program will produce the same value or not. Therefore this behavior might change in the future. [Although I believe the current behavior is a deliberate choice]
eq? checks if the objects are the same (think "if the pointer refers to the same address in memory").
In the first case you're working with literals created at compile time. Comparing (and modifying) literals is generally undefined behaviour. Here it looks like procedure x returns the same literal every time, but in the second expression it looks like the 2 literals are not the same. As I said, undefined behaviour.
In the second case you're not working with literals but list creates a new list at execution time. So each call to y or list creates a fresh list.
uselpa's answer is correct.† I wanted to expand on what a quoted datum is, a little further, though.
As you know, all Scheme programs are internally read in as a syntax tree. In Racket, in particular, you use the read-syntax procedure to do it:
> (define stx (with-input-from-string "(foo bar)" read-syntax))
> stx
#<syntax::1 (foo bar)>
You can convert a syntax tree to a datum using syntax->datum:
> (syntax->datum stx)
'(foo bar)
quote is a special form, and what it does is return the quoted portion of the syntax tree as a datum. This is why, for many Scheme implementations, your x procedure returns the same object each time: it's returning the same portion of the syntax tree as a datum. (This is an implementation detail, and Scheme implementations are not required to have this behaviour, but it helps explain why you see what you see.)
And as uselpa's answer says, list creates a fresh list each time, if the list is non-empty. That's why the result of two separate non-empty invocations of list will always be distinct when compared with eq?.
(In Scheme, the empty list is required to be represented as a singleton object. So (eq? '() '()) is guaranteed to be true, as is (eq? (list) '()), (eq? (cdr (list 'foo)) (list)), etc.)
† I would not use the phrasing "undefined behaviour" for comparing literals because that's easily confused with the C and C++ meaning of UB, which is nasal demons, and although the result of comparing literals may not be what you expect, it would not cause your program to crash, etc. Modifying literals is nasal demons, of course.

Contradictory assumptions on evaluator in SICP

Exercise 1.6 defines a new-if with cond:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
This new-if would fall into infinite loop when called in a recursion.
Example sqrt-iter illustrates the fact that arguments are evaluated immediately after passing into a user-defined function.
The (infinite)stream introduced in 3.5 is also defined a function:
(define (cons-stream a b)
(cons a
(delay b)))
The key point to build it, according to the text book, is delay.
But supposed you build a stream:
(define (intgers-starting-from n)
(cons-stream n
(intgers-starting-from (+ n 1))))
(define integers (intgers-starting-from 1))
Using the same evaluator as it in new-if, you won't get it working because (intgers-starting-from n) would always evaluate (intgers-starting-from (+ n 1)) and obviously there is no end to it despite how delay is implemented.
Is it contradictory that SICP assumes such evaluator that works for cons-stream but not for new-if?
SICP says:
Cons-stream is a special form defined so that
(cons-stream <a> <b>)
is equivalent to
(cons <a> (delay <b>))
It also adds:
Although stream-car and stream-cdr can be defined as procedures, cons-stream must be a special form. If cons-stream were a procedure, then, according to our model of evaluation, evaluating (cons-stream <a> <b>) would automatically cause <b> to be evaluated, which is precisely what we do not want to happen. For the same reason, delay must be a special form, though force can be an ordinary procedure.
By definition, a special form is not a procedure or function. So, your definition of cons-stream is incorrect.
It's usually implemented as a macro:
(define-syntax cons-stream
(syntax-rules ()
((cons-stream a b)
(cons a (delay b)))))
Indeed, you can define new-if as a macro and it'd work correctly too:
(define-syntax new-if
(syntax-rules ()
((new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))))

Which is the current continuation in the following expression?

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.).

Environment not part of a continuation?

Is the environment not part of a continuation in scheme?
I have tested this with Chicken, Gauche, Racket and Gambit, and they all behave similarly:
(define kont #f)
(let ((a 1)
(b 2))
(call-with-current-continuation
(lambda (k)
(set! kont k)
(display 'mutating)
(newline)
(set! a -1)
(set! b -2)))
(display (+ a b))
(newline))
I would expect -3 when the LET is evaluated, but +3 in the calls to kont (since I thought the program would remember the bindings of a and b before mutation):
(let ... ) ; <-- evaluating the LET above
; prints "mutating"
=> -3
(kont 100)
=> -3
(kont 100)
=> -3
So the continuation only affects control, and not the environment? In this case, why is it said that one of the ways to implement continuations is to "copy the stack" (are bindings are not on the stack?)
The continuation captures the bindings. However, as you surmise, these bindings are mutable.
You've been somewhat misled, here, by the "copies the stack" slogan. While this is a reasonable way to think about call/cc, it's not the whole story. For one thing, you really really wouldn't want a language feature that exposed whether or not local bindings were stack-allocated or not.
Instead, call/cc is defined using the notion of "program contexts". For a nice treatment of this, you might want to take a look at Shriram Krishnamurthi's (free, online) textbook PLAI, or at the (not-free, much more in-depth) book "Semantics Engineering with PLT Redex".
As an aside; your program doesn't really check what you wanted it to check, because you never invoked the captured continuation. I think you wanted to write something like this:
#lang racket
(define kont #f)
(let ([a 3])
(let/cc k
(set! kont k)
(set! a 4))
(printf "~s\n" a))
(kont)
... which shows pretty much the same behavior that you mention above.
You change the values of a and b in the environment with set!. So a and b is -1 and -2 in the continuation environment. You can not unroll side effects. There are no differences between a, b and kont in your continuation.

How can i overload a function at run time in Scheme?

rt.
I want to redefine a function at run time so that i can change the behavior of the system at run time.
thanks.
(define (foo x) ...stuff...)
(set! foo (lambda (x) ...different stuff...))
It might be advisable to use let to do this locally, this can also apply to keywords in this sense:
(let ((define +))
(define 2 3)) ; ===> 5
Or even redefine them to constants, remember, Scheme is a lisp-1:
(let ((define 2) (+ 4))
(- define +)) ; ===> -2
Or even:
(let ((quote /))
'3) ===> 1/3
Doing it only locally preserves the functional style.
Assuming you want to overload a function you defined earlier, simply define it again. This also works for redefining functions such as car and cdr, e.g. to make car into cdr:
(define (car x) (cdr x))
However, I think you won't be able to affect other already defined functions with such a redefinition, so a system function which uses car will still use the original system car and not yours:
(define (test x) (car x))
(define (car x) (cdr x))
(test '(1 2 3))
1
I guess the reason for this is that internally the symbols disappear once a function gets read or evaluated and the symbols are replaced by what they're bound to; in this case, the actual code of the function. So rebinding a symbol to a different function won't affect the rest of your already defined code. This is usually a good thing because it helps uphold referential transparency.
If you want to redefine scheme keywords such as lambda or cond, use let-syntax (see http://community.schemewiki.org/?scheme-faq-language)

Resources