# Dealing with multiple values

**URL:** <https://racket.discourse.group/t/dealing-with-multiple-values/3500>\
**Category:** Show & Tell\
**Created:** [January 19, 2025, 2:21pm UTC](https://racket.discourse.group/t/dealing-with-multiple-values/3500 "2025-01-19T14:21:59Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![matteo-daddio](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/matteo-daddio/32/1245_2.png) [@matteo-daddio](https://racket.discourse.group/u/matteo-daddio)\
**Post date:** [January 19, 2025, 2:21pm UTC](https://racket.discourse.group/t/dealing-with-multiple-values/3500/1 "2025-01-19T14:21:59Z")

</div>

Hello,

some months ago, when I started working with streams, I developed a procedure that takes some single valued streams and return a multi valued stream. Then I thought if the opposite was possible: create a procedure that takes a multi valued stream and return a list of single valued streams. Probably such a procedure isn't very useful, but the solution is interesting.

I developed some macros to deal with multiple values:

```scheme
(define-syntax values->list ;I didn't use this, but is a good starting point
  (syntax-rules ()
    [(_ (values lst ...))
     (call-with-values
      (lambda () (values lst ...))
      (lambda v v))]))

(values->list (values 1 2 3))
=> '(1 2 3)

(define-syntax num-of-values
  (syntax-rules ()
    [(_ (values lst ...))
     (call-with-values
      (lambda () (values lst ...))
      (lambda v (length v)))]))

(num-of-values (values 1 2 3))
=> 3

(define-syntax values-ref
  (syntax-rules ()
    [(_ (values lst ...) n)
     (call-with-values
      (lambda () (values lst ...))
      (lambda v (list-ref v n)))]))

(values-ref (values 1 2 3) 1)
=> 2

```

With these procedures the solution is simple:

```scheme
(define (stream-select the-stream n)
  (if (stream-empty? the-stream)
      empty-stream
      (stream-cons (values-ref (stream-first the-stream) n)
                   (stream-select (stream-rest the-stream) n))))

(define (mv-stream->list-of-streams the-stream)
  (define num-of-vals (num-of-values (stream-first the-stream)))
  (let next-streams ([n 0])
    (if (= n num-of-vals)
        '()
        (cons (stream-select the-stream n)
              (next-streams (+ n 1))))))

(define mv-stream (stream (values 1 10 100)
                          (values 2 20 200)
                          (values 3 30 300)
                          (values 4 40 400)))

(define los (mv-stream->list-of-streams mv-stream))

(stream->list (first los))
(stream->list (second los))
(stream->list (third los))

'(1 2 3 4)
'(10 20 30 40)
'(100 200 300 400)

```

Matteo

---

<div class="post-metadata">

**Author:** ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)\
**Post date:** [January 19, 2025, 3:09pm UTC](https://racket.discourse.group/t/dealing-with-multiple-values/3500/2 "2025-01-19T15:09:43Z")

</div>

Here are some possible improvements:

First, macros operate on compile-time syntax objects, not run-time values. Consider:

```scheme
(define-syntax num-of-values
  (syntax-rules ()
    [(_ (values lst ...))
     (call-with-values
      (lambda () (values lst ...))
      (lambda v (length v)))]))

```

With the above macro, when we do `(num-of-values (stream-first the-stream))`, we would have `values` = `stream-first` and `lst ...` = `the-stream`. I don’t think that’s what you intend.

It would suffice to write:

```scheme
(define-syntax num-of-values
  (syntax-rules ()
    [(_ vals)
     (call-with-values
      (lambda () vals)
      (lambda v (length v)))]))

```

With the revised macro, when we do `(num-of-values (stream-first the-stream))`, we would have `vals` = `(stream-first the-stream)`.

---

<div class="post-metadata">

**Author:** ![matteo-daddio](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/matteo-daddio/32/1245_2.png) [@matteo-daddio](https://racket.discourse.group/u/matteo-daddio)\
**Post date:** [January 19, 2025, 8:10pm UTC](https://racket.discourse.group/t/dealing-with-multiple-values/3500/3 "2025-01-19T20:10:22Z")

</div>

Thank you Sorawee, my version didn't convince me from the beginning, I was surprised it worked. Now it’s clear.

Matteo

---

<div class="post-metadata">

**Author:** ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)\
**Post date:** [January 19, 2025, 11:20pm UTC](https://racket.discourse.group/t/dealing-with-multiple-values/3500/4 "2025-01-19T23:20:33Z")

</div>

Ughh, Discourse cuts content in my email again 😕 Here's the missing part:

Second, doing `list-ref` in a loop takes quadratic time. Here’s a test to demonstrate the problem:

```scheme
(define my-stream
  (stream (apply values (range 0 20000))
          (apply values (range 20000 40000))))

(define los (mv-stream->list-of-streams my-stream))
(time (void (map stream->list los))) 
;=> cpu time: 3134 real time: 3396 gc time: 272

```

Here’s a revision that fixes the quadratic time issue:

```scheme
;; the-stream must be a non-empty stream
(define (mv-stream->list-of-streams the-stream)
  (define st
    (for/stream ([e (in-values-sequence (in-stream the-stream))])
      e))
  (define num-of-vals (length (stream-first st)))
  (let loop ([n 0] [st st])
    (cond
      [(= n num-of-vals) '()]
      [else
       (define fst
         (for/stream ([xs (in-stream st)])
            (first xs)))
       (define rst
         (for/stream ([xs (in-stream st)])
            (rest xs)))
       (cons fst (loop (add1 n) rst))])))

(define my-stream
  (stream (apply values (range 0 20000))
          (apply values (range 20000 40000))))

(define los (mv-stream->list-of-streams my-stream))
(time (void (map stream->list los))) 
;=> cpu time: 30 real time: 31 gc time: 6

```
