Georg Fuss
Georg Fuss

Reputation: 315

The procedure "values"

In the answer to his own question "My code signals the error “application: not a procedure” or “call to non procedure” sylwester on Jan. 2. showed this example

(define (abs x)
       ((if (< x 0) - values) x))

I do not understand the explanation of the procedure "values" in the MIT/Gnu-Reference for scheme. I am wondering, why (display (values 1 2 3)) gives

[compiled-closure 23 (global #x3b) #x7b #x1845c93 #x324eaa8]

;Unspecified return value

Upvotes: 0

Views: 92

Answers (2)

Georg Fuss
Georg Fuss

Reputation: 315

In Gnu/MIT-Scheme there two uses for "values"

That, what you have in mind: Some lines from the reference:

from chapter 12.4 values object . . . [procedure] Returns multiple values. The continuation in effect when this procedure is called must be a multiple-value continuation that was created by call-with-values. Furthermore it must accept as many values as there are objects.

That is, why your example

(define (abs x)
  ((if (< x 0) - values) x))

works.

In 14.11.2 *Parser values expression . . . [parser expression] Sometimes it is useful to be able to insert arbitrary values into the parser result. The values expression supports this. The expression arguments are arbitrary Scheme expressions that are evaluated at run time and returned in a vector. The values expression always succeeds and never modifies the internal pointer of the parser buffer.

Examples for the second definition, which does not work

(values 5)
;Value 29: #[compiled-closure 29 ("global" #x3b) #x7b #xf4cc93 #x2b87bc0]

(define (double x)
  (* (values x) 2))
(double 5) 
;The object #[compiled-closure 27 ("global" #x3b) #x7b #xf4cc93 #x2b69808], passed as the first argument to integer-zero?, is not the correct type.

Dear sylwester, thank you for your effort.1

Upvotes: 0

Sylwester
Sylwester

Reputation: 48765

values works as the identity function:

(values 5)         ; ==> 5
((lambda (v) v) 5) ; ==> 5

Now values also allows for other than just one value. If you do (values 4 5) it will send both back.

If you do (display expression) then display will be the continuation of expression and it only accept one argument while (values 1 2 3) will pass it 3. For a R5RS it would be invalid Scheme code and thus while it is advised by the report to have a sensible error message signalled the implementation is free to do what they please. In reality that opens up for implementation specific and unportable features.

Here is an example of using values with other than one argument:

;;  returns the max and min value from the list with at least one element.
(define (min-max lst)
  (let loop ((lst (cdr lst)) (min-value (car lst)) (max-value (car lst)))
    (if (null? lst)
        (values min-value max-value)
        (let ((a (car lst)))
          (loop (cdr lst) (min min-value a) (max max-value a))))))

(min-max '(1 2 3 4 5 6))
; ==> 1
; ==> 6

;; sums the max and min object from the list
(define (sum-min-max lst)
  (let-values (((min max) (min-max lst)))
    (+ min max)))

(sum-min-max '(1 2 3 4 5 6))
; ==> 7

Scheme has functions that return multiple values. One example is div-and-mod in the R6RS:

(div-and-mod 13 5)
; ==> 2
; ==> 3

In Scheme the receiving function needs to support the number of arguments while in CL a multiple value result that is not handles is handles as if it only returned the first value.

(print (values 1 2 3))
; ==> 1 (as side effect it prints 1)

I've always wondered why Scheme didn't copy this feature as div and div-and-mod both calculates the remainder in the CPU so they are essentially the same thing with the exception of how many values it returns. The CL equivalent only has one function where you choose to use it in single value context or not.

Upvotes: 0

Related Questions