Thursday 9 July 2020

(practical-python->racket exercise 1.8 extra payments)

The second exercise takes the first a step further by calculating the affect of making an additional monthly payment of 1,000 dollars in the first year of the loan. Having come up with two versions of the mortgage payment example, which should I use for this example? I felt I'd get the most out of the exercise if I again came up with "HTDP" and "practical" versions.

Starting with the "HTDP" version, I realised that there was one improvement that I could make before I even started on the improvements. I added some constant definitions to add a little clarity:

; constants
(define LOAN_AMOUNT 500000.00)
(define INTEREST_RATE 0.05)
(define MONTHLY_PAYMENT 2684.11)

and changed the definition of "daves-mortgage":

(define daves-mortgage
  (make-mortgage LOAN INT_RATE MTHLY_PAYMENT 0 0.00))


This trivial change put me in a "refactoring" frame of mind. The next step I took was to wrap the superficially direct use of the mortgage-payment field in a function. This turned out to be a little heavier than I expected as I needed to pass the whole mortgage structure to the wrapper function (so that I can later calculate additional payment amounts.

This is the simple wrapper function:
(check-within (payment (make-mortgage 1000 .10 100 0.00 0.00))
                       100
                       1e-5)
(define (payment mortgage)
  (mortgage-payment mortgage))


When I came to actually make the changes to reflect the additional payments, there was a nuance due to the way that I was feeding the data back into the pay function recursively. I only needed to increase the payment by 1,000 dollars in the first month and then decrease it by 1,000 dollars in the 13th month. This is the resulting payment function:

(define (payment mortgage)
  (cond
    [(= (mortgage-num-payments mortgage) 0)
     (+ (mortgage-payment mortgage) 1000)]
    [(= (mortgage-num-payments mortgage) 12)
     (- (mortgage-payment mortgage) 1000)]
    [else (mortgage-payment mortgage)]))


The only other significant change was to return both the total paid and the number of months from the main pay function. I choose to return the two values as a pair. (A datatype I only learnt about when reading the Data Types chapter of The Racket Guide). I then used car and cdr to extract the two items from the pair. (It made me feel like a real lisp programmer ;-) ).


One area where my practical knowldege of Racket is severely lacking is formatting simple output. I really need to learn the Racker equivalent of Python's print(f'The number is {i}') or even print(i ,j).

Making the changes to the "practical" version was straightforward. I even remembered to use when instead of if. (if requires expressions for both the "then" and "else" cases.

The final programs are ex_1_8_extra_payments.rkt and ex_1_8_extra_payments_2.rkt

Now on to the rest of the exercises.


No comments: