Reputation:
I'm having problems implementing one generator called fib
in a function.
I want the function to return me a generator that generates the first n
Fibonacci numbers.
;THIS IS MY GENERATOR
(define fib
(let ((a 0) (b 1))
(lambda ()
(let ((return a))
(set! a b)
(set! b (+ b return)
)return))))
;THIS IS MY FUNCTION
(define (take n g)
(define fib
(let ((a 0) (b 1) (cont 1))
(lambda ()
(if (>= cont n) #f
(let ((return a))
(set! cont (+ cont 1))
(set! a b)
(set! b (+ b return)
)(return)))))))
I expect a generator to return the Fibonacci numbers up to N
(delivered to the function). But the actual output is :
begin (possibly implicit): no expression after a sequence of internal definitions in:
(begin (define fib (let ((a 0) (b 1) (cont 1)) (lambda () (if (>= cont n) #f (let ((return a)) (set! cont (+ cont 1)) (set! a b) (set! b (+ b return)) (return)))))))
Upvotes: 2
Views: 3595
Reputation: 71119
Just as the error says, you have no expressions in your function's definition except for some internal definition (which, evidently, is put into an implicit begin
). Having defined it, what is a function to do?
More importantly, there's problems with your solution's overall design.
When writing a function's definition, write down its sample calls right away, so you see how it is supposed / intended / to be called. In particular,
(define (take n g)
suggests you intend to call it like (take 10 fib)
, so that inside take
's definition g
will get the value of fib
.
But fib
is one global generator. It's not restartable in any way between different calls to it. That's why you started copying its source, but then realized perhaps, why have the g
parameter, then? Something doesn't fit quite right, there.
You need instead a way to create a new, fresh Fibonacci generator when you need to:
(define (mk-fib)
(let ((a 0) (b 1))
(lambda ()
(let ((ret a))
(set! a b)
(set! b (+ ret b))
ret)))) ;; ..... as before .....
Now each (mk-fib)
call will create and return a new, fresh Fibonacci numbers generator, so it now can be used as an argument to a take
call:
(define (taking n g) ;; (define q (taking 4 (mk-fib)))
Now there's no need to be defining a new, local copy of the same global fib
generator, as you were trying to do before. We just have whatever's specific to the take
itself:
(let ((i 1))
(lambda () ; a generator interface is a function call
(if (> i n) ; not so good: what if #f
#f ; is a legitimately produced value?
(begin
(set! i (+ i 1))
(g)))))) ; a generator interface is a function call
Now we can define
> (define q (taking 4 (mk-fib)))
> (q)
0
> (q)
1
> (q)
1
> (q)
2
> (q)
#f
> (q)
#f
>
Upvotes: 2