3

R5RS says...

Values might be defined as follows:

(define (values . things)
  (call-with-current-continuation
    (lambda (cont) (apply cont things))))

It doesn’t, however, say how call-with-values might be implemented if values were implemented this way. So, if values is implemented this way, how would call-with-values be implemented?

(This came up because I was trying to get some code that used call-with-values to work with TinyScheme, which doesn’t support it. I managed by faking values and call-with-values with lists, but—when I saw this in R5RS—I wanted to know if this might be a better workaround.)

Nick Andriopoulos
  • 10,313
  • 6
  • 32
  • 56
Robert Fisher
  • 578
  • 4
  • 20

2 Answers2

3

Kent Dybvig defines call/cc, values and call-with-values thusly:

(define call/cc call/cc)
(define values #f)
(define call-with-values #f)
(let ((magic (cons 'multiple 'values)))
  (define magic?
    (lambda (x)
      (and (pair? x) (eq? (car x) magic)))) 

  (set! call/cc
    (let ((primitive-call/cc call/cc))
      (lambda (p)
        (primitive-call/cc
          (lambda (k)
            (p (lambda args
                 (k (apply values args))))))))) 

  (set! values
    (lambda args
      (if (and (not (null? args)) (null? (cdr args)))
          (car args)
          (cons magic args)))) 

  (set! call-with-values
    (lambda (producer consumer)
      (let ((x (producer)))
        (if (magic? x)
            (apply consumer (cdr x))
            (consumer x))))))
user448810
  • 17,381
  • 4
  • 34
  • 59
  • This is a good answer in that it answers the need to implement values and call-with-values for an implementation that lacks them. I’m really hoping for a call-with-values implementation that is compatible with the values example from R5RS or explains why it can’t be done. – Robert Fisher May 23 '13 at 15:32
  • Why is call/cc included? Will these versions of values and call-with-values work without this call/cc? – Robert Fisher May 23 '13 at 15:35
  • Read the link to Dybvig's original (on the word "thusly"); all I did was copy it. But I'm pretty sure the answer is "no." – user448810 May 23 '13 at 16:11
1

The short answer is: You can't

The nifty implementation of values does not change the fact that there is no way to implement the other procedures if you don't have any of them to poke at the values. If you had one way to peek then you could implement the others with that.

(+ (values 4 5))
(apply + (values 4 5))

Doesn't work and that's why you need those other primitives.

When that said. There is no difference between returning more values and returning lists with values since the difference is optimization. You could make a macro that treats both of them as a binding and then the way you use them would be the same. The difference in performance is some pointer jumping and some consing which is reasonable fast for any lisp implementation. Heres a minimalistic implementation that will work given your code is correct:

(define values list)
(define (call-with-values producer consumer)
  (apply consumer (producer)))
Sylwester
  • 47,942
  • 4
  • 47
  • 79
  • The list-based versions you give are exactly what I used. It should be noted that—in addition to the optimization difference—a “real” implementation of values can be used as an identity function, which this workaround breaks. (And I actually ran into that in the code I was using.) – Robert Fisher May 28 '13 at 14:33
  • 1
    @RobertFisher By using the magic token trick of Kent Dybvig you get it to function as identity. RnRS spec is (also) there for implementers so it is a implementation hint in my mind. I imagine (fun a) => b just before apply would have a,fun on stack before applying and b,continuation after in a fully CPS-ed scheme. – Sylwester May 28 '13 at 17:13