问题
Goal: implement unfold
function using only two arguments.
The arguments:
- the first argument is f which takes an initial value of some type I and returns nil or a cons pair of two elements (the first of these two is the next element that goes in the list of some type A and the next initial value again of some type I).
- The second argument is an initial value of some type I and the return is a list of items of type A.
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?
回答1:
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)))))
来源:https://stackoverflow.com/questions/9286014/unfold-function-in-scheme