Exercise 2.35 asks us to redefine the
count-leaves
procedure from section 2.2.2 as an accumulation. Our procedure should take the following form:(define (count-leaves t)
(accumulate <??> <??> (map <??> <??>)))
When I encounter a problem like this (implement X in terms of Y), I find that it helps to take a look at both procedures side-by-side to see what they have in common. The
count-leaves
procedure just returns 1 when it encounters each leaf node, and recursively combines all those 1s with addition otherwise.; count-leaves from sicp section 2.2.2
(define (count-leaves x)
(cond ((null? x) 0)
((not (pair? x)) 1)
(else (+ (count-leaves (car x))
(count-leaves (cdr x))))))
The
accumulate
procedure takes an operator, and initial value, and a sequence as its parameters. It then combines all elements of the sequence with the initial value using the operator.; accumulate from sicp section 2.2.3
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
The operator and initial value in the case of
count-leaves
are pretty easy to guess. They should be + and 0 respectively. For its third argument accumulate
is expecting a sequence, and our template is using map
. Recall that map
takes a function and a list and returns a new list. The new list is simply the result of the function being applied to each element of the old list. What we'd really like to accumulate is a sequence of 1s, one for each leaf in the tree. To implement that we need the help of one more procedure from SICP section 2.2.3.; enumerate-tree from sicp 2.2.3
(define (enumerate-tree tree)
(cond ((null? tree) null)
((not (pair? tree)) (list tree))
(else (append (enumerate-tree (car tree))
(enumerate-tree (cdr tree))))))
The
enumerate-tree
procedure "flattens out" a tree into a sequence of its leaves. Once we have the tree in the form of a sequence, we just need to define a function for the first argument of map
. This function should simply return a 1 for any input. Here's the complete (but very short) solution.(define (count-leaves t)
(accumulate + 0 (map (lambda (x) 1)
(enumerate-tree t))))
Test it out with trees of different shapes, just to be sure there are no corner cases missed.
> (count-leaves (list))
0
> (count-leaves (list 1 2 3))
3
> (count-leaves (list 1 (list 1 2 3)))
4
> (count-leaves (list (list 1 2) (list 1 2 3) 1))
6
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
3 comments:
I came up with another solution without map:
(define (count_leaves tree)
(accumulate (lambda (x y)
(if (list? x)
(+ (count_leaves x) y)
(+ 1 y)))
0
tree))
Another solution:
(define (count-leaves t)
(accumulate + 0 (map (lambda (x)
(if (pair? x)
(count-leaves x)
1))
t)))
I don't understand this:
(define (count-leaves t)
(accumulate + 0 (map (lambda (x) 1)
(enumerate-tree t) )))
(define (map proc items)
(if (null? items)
null
(cons (proc (car items))
(map proc (cdr items)))))
Which translate to:
(define (map 1 items)
(if (null? items)
null
(cons (1(car items))
(map 1(cdr items)))))
How does that work?1 is not a procedure
Post a Comment