3

I have the code

(define alternate
(letrec ([f (lambda (x) (cons x (lambda () (f (+ x 1)))))])
(lambda () (f 1))))

The result is 1,2,3.. How i could change it to take 1,2,1,2,1,2..

I tried cons inside the f but didn't work. Any ideas?

Óscar López
  • 232,561
  • 37
  • 312
  • 386
Rea
  • 67
  • 5

3 Answers3

1

This is straightforward to implement using streams:

(define (alternate)
  (stream-map (lambda (x)
                (if (even? x) 1 2))
              (in-naturals)))

The trick here is that a stream is built using stream-cons, which basically does what you're implementing by hand: it creates a list where its elements are "promises" that get evaluated only when needed.

stream-cons produces a lazy stream for which stream-first forces the evaluation of first-expr to produce the first element of the stream, and stream-rest forces the evaluation of rest-expr to produce a stream for the rest of the returned stream.

This shows how alternate returns an infinite stream of elements of the form 1 2 1 2 1 2 ...

(define alt (alternate))

(stream-ref alt 0)
=> 1
(stream-ref alt 1)
=> 2
(stream-ref alt 2)
=> 1
(stream-ref alt 3)
=> 2

Alternatively, if you need a list of n elements of the sequence use this procedure, which by the way should be part of Racket in the first place:

(define (stream-take s n)
  (if (zero? n)
      '()
      (cons (stream-first s)
            (stream-take (stream-rest s) (sub1 n)))))

Now it works as expected:

(define alt (alternate))

(stream-take alt 0)
=> '()
(stream-take alt 1)
=> '(1)
(stream-take alt 2)
=> '(1 2)
(stream-take alt 3)
=> '(1 2 1)
Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • I use a function to call the stream n times.If i call it once i want '(1).2nd: '(1 2) 3rd time: '(1 2 1) 4th time: '(1 2 1 2).This stream doesn't work this way..:( – Rea Feb 24 '13 at 22:52
  • @Rea it's quite possible to get that result with my implementation, see my updated answer for a solution – Óscar López Feb 24 '13 at 22:59
1

You might also find generators useful: docs

Welcome to DrRacket, version 5.3.3.5 [3m].
Language: racket [custom].
> (require racket/generator)
> (define g (generator () (let LOOP () (yield 1) (yield 2) (LOOP))))
> (g)
1
> (g)
2
> (g)
1
> (g)
2

UPDATE:

Even better, use an infinite-generator:

Welcome to DrRacket, version 5.3.3.5 [3m].
Language: racket [custom].
> (require racket/generator)
> (define g (infinite-generator (yield 1) (yield 2)))
> (g)
1
> (g)
2
> (g)
1
> (g)
2
stchang
  • 2,555
  • 15
  • 17
0

Here's a way to do it as a small modification of your existing code:

(define alternate
  (letrec ([f (lambda (x) (cons x (lambda () (f (if (= x 1) 2 1)))))])
    (lambda () (f 1))))
jacobm
  • 13,790
  • 1
  • 25
  • 27