-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsol-2.29.tex
88 lines (77 loc) · 3.92 KB
/
sol-2.29.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
\begitems\style a
* \removettskip\begtt\scm
(define (left-branch mobile)
(car mobile))
(define (right-branch mobile)
(cadr mobile))
(define (branch-length branch)
(car branch))
(define (branch-structure branch)
(cadr branch))
\endtt
* \removettskip\begtt\scm
(define (total-weight mobile)
(+ (branch-weight (left-branch mobile))
(branch-weight (right-branch mobile))))
(define (branch-weight branch)
(if (mobile? (branch-structure branch))
(total-weight (branch-structure branch))
(branch-structure branch)))
(define (mobile? structure)
(pair? structure))
\endtt
* A straightforward way to determine whether a mobile is balanced or not is to recursively compute the torque applied to its branches by making use of the above defined `total-weight` procedure:
\begtt\scm
(define (balanced? mobile)
(let ((left (left-branch mobile))
(right (right-branch mobile)))
(and (= (* (branch-length left) (branch-weight left))
(* (branch-length right) (branch-weight right)))
(or (not (mobile? (branch-structure left)))
(balanced? (branch-structure left)))
(or (not (mobile? (branch-structure right)))
(balanced? (branch-structure right))))))
\endtt
Anyhow, this method is not efficient, because it performs a lot of redundant computations---weights of mobiles (except for the top-level one) are computed multiple times\fnote{The tree-recursive process generated by this procedure is similar to that generated by the `fib` procedure of section~1.2.2.}.
Another more efficient way to test if a mobile is balanced, is to avoid using the `total-weight` procedure, and instead let the `balanced?` procedure directly compute and return the weight of the given mobile when the mobile is balanced:\fnote{This is fine because in Scheme anything other than `#f` is treated as true, so returning the value `#t` is not strictly necessary.}
\begtt\scm
(define (balanced? mobile)
(let ((left (left-branch mobile))
(right (right-branch mobile)))
(let ((left-result (if (mobile? (branch-structure left))
(balanced? (branch-structure left))
(branch-structure left)))
(right-result (if (mobile? (branch-structure right))
(balanced? (branch-structure right))
(branch-structure right))))
(and left-result
right-result
(= (* (branch-length left) left-result)
(* (branch-length right) right-result))
(+ left-result right-result)))))
\endtt
Furthermore, with a slight modification, we can avoid exploring the remaining mobiles as soon as we find a mobile that is not balanced:
\begtt\scm
(define (balanced? mobile)
(let ((left (left-branch mobile))
(right (right-branch mobile)))
(let ((left-result (if (mobile? (branch-structure left))
(balanced? (branch-structure left))
(branch-structure left))))
(and left-result
(let ((right-result (if (mobile? (branch-structure right))
(balanced? (branch-structure right))
(branch-structure right))))
(and right-result
(= (* (branch-length left) left-result)
(* (branch-length right) right-result))
(+ left-result right-result)))))))
\endtt
* In principle, when we modify the constructors of mobiles and branches, we may need to modify the corresponding selectors and also the procedure `mobile?` that we used to tell if a structure is a mobile, since they constitute the abstraction barriers that we built to interact with mobiles and branches without knowing their representation. In this particular case, however, only few changes are required:
\begtt\scm
(define (right-branch mobile)
(cdr mobile))
(define (branch-structure branch)
(cdr branch))
\endtt
\enditems