3

From the R5RS standard:

Values might be defined as follows:
(define (values . things)
  (call-with-current-continuation
    (lambda (cont) (apply cont things))))

My first interpretation of this was that an expression like (+ (values 1 2)) is equivalent to (apply + '(1 2)) and would yield the result 3. But, according to my tests, this interpretation is not correct. Here is my interpretation of the code above: values is a function taking any number of arguments, bundled into a list called things. Then, the current continuation (the place where values is used) is called with the list things "unbundled".

What am I missing? The example above (+ (values 1 2)) gives an error or 1 depending on the interpreter I used.

Gradient
  • 2,253
  • 6
  • 25
  • 36

2 Answers2

5

See, when you type

(+ (values 1 2))

the continuation of the call to values is actually a single argument to +. So, it is either treated as 1 (the first element to the list, the first value produced by the procedure), or an error. R5RS says in this regard:

Except for continuations created by the call-with-values procedure, all continuations take exactly one value. The effect of passing no value or more than one value to continuations that were not created by call-with-values is unspecified.

On the other hand, call-with-values would correctly bind your list's elements to its consumer argument's formal arguments:

Calls its producer argument with no values and a continuation that, when passed some values, calls the consumer procedure with those values as arguments.

bipll
  • 11,747
  • 1
  • 18
  • 32
  • 1
    Ah, I see! I tested `(+ (values 1))` and it works in the interpreter that gave an error to `(+ (values 1 2))`. – Gradient Apr 04 '18 at 05:25
2

In order to understand what this definition of values means, you need to also understand the definition of call-with-current-continuation, which it is defined in terms of. And helpfully, the documentation for values mentions call-with-values, as an example of how to use the result of values.

So, you could use (values 1 2) in a context like:

(call-with-values (lambda () (values 1 2))
                  (lambda (x y) (+ x y)))
amalloy
  • 89,153
  • 8
  • 140
  • 205