Taking a break from the Simply Scheme book to work on some exercises of my own in order to develop some skills.
Composability of If
Exercise 1
I made up this exercise myself to work on internalizing the idea of the if procedure being composable that is discussed in chapter 6 of Simply Scheme. The program figures out whether it is election day based on user input
1
2
3
4
5
6
|
(define (election-day month day year)
(se 'It
(if (and (= 11 month)(= 3 day)(= 2020 year))
'(is Election Day)
'(is not Election Day))))
|
Test cases:
1
2
3
4
5
6
|
(election-day 11 3 2020)
It is Election Day
(election-day 11 4 2020)
It is not Election Day
|
Exercise 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
(define (bank-account-status amount)
(se '(Your account)
(if (< amount 0)
(se '(is overdrawn by) (word amount) 'dollars)
(se 'balance 'is (word "$" amount) 'dollars))))
(bank-account-status -50)
;'(Your account is overdrawn by -50 dollars)
(bank-account-status 200)
;'(Your account balance is $200 dollars)
|
Ran into an issue with this one. I initially didn’t use (se
for the parts inside the if
. I was thinking that I should just be able to pass multiple arguments to the se
for the overall program – the one next to '(Your account).
se
does indeed take multiple arguments, but if
does not, so if you want to use if
like I do you have to group the things together. And you can’t just call procedures from inside a sentence – you can’t do e.g.
1
2
|
'(is overdrawn by (word '$ 500) 'dollars)
|
If I just enter that in Scheme, I get back '(is overdrawn by (word '$ 500) 'dollars)
. Scheme thinks the stuff inside the attempted invocation of word
is just part of the sentence. So for what I want to do above, I need something that will let me call stuff like word
and combine that with other stuff, grouping that into a single argument which the if
can return and which the first se
can take as an argument. And for my purposes se
is what does that.
Nested Ifs
Exercise 1
I made a program to test my understanding of how to use nested if procedures.
Context: For U.S. Presidential elections, if no one wins a majority of electoral votes, then the incoming (newly-elected) House of Representatives selects the President, and each state House delegation from the states gets 1 vote. So the party that controls a majority of state House delegations in the incoming House of Representatives will pick the President.
There are 538 Electoral Votes up for grabs. I assume that it’s a two-man race and no votes will go to anyone else.
The program attempts to represent the following state of affairs:
– If Trump gets less than 50% of electoral votes (less than 269), that’s an outright loss. So he just loses, the end.
– If Trump gets exactly 50% of electoral votes (exactly 269), then he wins if the GOP controls a majority of the state delegations in the House. Trump loses if they do not control a majority of state House delegations.
– If Trump gets more than 50% of electoral votes (270 or higher) then he just wins.
The way I actually represented this in the program was as follows:
If Trump gets less than 269 electoral votes, he loses. Alternatively, we go to if #2.
Within if #2, if Trump has exactly 269 electoral votes, then we go to the next if statement. Otherwise, Trump wins (sine we covered \< 269 and = 269, > 269 is the only possibility left, and Trump wins in that case).
Within if #3 (where, again, Trump has exactly 269 electoral votes), if house-state-delegation-control
does NOT equal gop, Trump loses. Otherwise, he wins.
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
|
<br /><br />(define (election-result trump-evs house-state-delegation-control)
(if (< trump-evs 269)
'(Trump loses)
(if (= trump-evs 269)
(if (not (equal? house-state-delegation-control 'gop))
'(Trump loses)
'(Trump wins!))
'(Trump wins!))))
; test cases:
(election-result 268 'gop)
;'(Trump loses)
(election-result 269 'gop)
;'(Trump wins!)
(election-result 269 'dem)
;'(Trump loses)
(election-result 270 'dem)
;'(Trump wins!)
(election-result 270 'gop)
;'(Trump wins!)
|
I made a tree of the logic of this program. I found the tree extremely helpful.
Analysis of buntine’s Valid Date Range Checker
I liked how a github user called buntine solved one of the Scheme problems (regarding a valid date range checker). His solution is here and pasted below. I wanted to understand the program better, so i decided to try describing it in words.
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
|
(define (divisible? x y)
(= (remainder x y) 0))
(define (valid-range? n bound)
(and (number? n) (> n 0) (> (+ 1 bound) n)))
(define (days-in-month m d y)
(cond
((= m 1) 31)
((= m 2)
(if (divisible? y 4)
(if (divisible? y 100)
(if (divisible? y 400)
29 28)
29)
28))
((= m 3) 31)
((= m 4) 30)
((= m 5) 31)
((= m 6) 30)
((= m 7) 31)
((= m 8) 31)
((= m 9) 31)
((= m 10) 30)
((= m 11) 30)
((= m 12) 31)
(else 0)))
(define (valid-date? m d y)
(and (valid-range? m 12)
(valid-range? d (days-in-month m d y))
(number? y)))
|
February Logic
I made a tree of the logic of the part of the program that handles February in order to help me understand it. I found it extremely helpful for this purpose.
The Program Generally
Commenting on the program as I go along, skipping divisible
:
1
2
3
|
(define (valid-range? n bound)
(and (number? n) (> n 0) (> (+ 1 bound) n)))
|
This predicate helper function offers a general solution to the problem of wanting to find whether a number is in a valid range. It checks if an argument is i) a number, and ii) greater than 0, and iii) less than a bound
which is defined by the second argument passed into the program. If all these conditions are met, it returns #t
. Otherwise, it returns #f
.
days-in-month
is a helper procedure that returns the number of days in a month depending on the month and year provided. The February logic is addressed in my tree above. If the value of the month is anything other than 1 through 12, days-in-month
returns 0
.
Finally, the main program:
1
2
3
4
5
|
(define (valid-date? m d y)
(and (valid-range? m 12)
(valid-range? d (days-in-month m d y))
(number? y)))
|
this program makes two calls to the valid-range?
procedure. the first checks that the number of months is 1 through 12 (the 12 gets used as the bound). the second call to valid-range?
is more interesting. the days-in-month procedure is used to generate the bound for checking the validity of the value for days d
. Finally, the year is checked to ensure it is a number. If all these checks are passed, the entire procedure returns #t
.