Reputation: 179
Goal: implement unfold
function using only two arguments.
The arguments:
This is what I have so far and I am not sure why it is not working:
(define (descending i)
(if (= i 0)
(list)
(cons i (- i 1))))
(define nil (list))
(define (unfold f init)
(if (eq? (f init) '())
(list)
(cons init (unfold f (f init)))))
(unfold (descending 5))
should evaluate to
'(5 4 3 2 1)
This should be the result but isn't. What am I doing wrong?
Upvotes: 3
Views: 1615
Reputation: 183873
First, it should be (unfold descending 5)
. Then f
would produce a pair and you would use both components of it,
(define (unfold f init)
(if (eq? (f init) '())
(list)
(cons (car (f init)) (unfold f (cdr (f init))))))
But this has awful computational complexity as it calls (f init)
three times per iteration. A humble let
binding remedies this.
(define (unfold f init)
(let ((r (f init)))
(if (empty? r) ;; instead of (eq? r '())
(list)
(cons (car r) (unfold f (cdr r))))))
And a tail recursive form using named let
(define (unfold f init)
(let loop ((acc empty)
(state (f init)))
(if (empty? state)
(reverse acc)
(loop (cons (car state) acc)
(f (cdr state))))))
And using match
.
(define (unfold f init)
(let loop ((acc empty)
(state (f init)))
(match state
((cons x next)
(loop (cons x acc)
(f next)))
(empty
(reverse acc)))))
Upvotes: 6