Monday, 13 July 2020

(practical-python->racket exercises 1.9 1.10 1.11)

The next step in the mortgage exercise is to "parameterise" the start month, end month and additional payment amount. It was fairly trivial to update the "practical" version to do so. The code is at ex_1_9_extra_payment_calculator_2.rkt.


To make the changes to the "HTDP" versions, I extended the main data structure to include the new data items. I had to be careful to adjust the number of payments before calculating the payment for a month. The code is at ex_1_9_extra_payment_calculator.rkt.



The penultimate step in the mortgage exercise is to display a table showing the total paid and outstanding balance for each month of the loan. For me, the sensible way to do this was to update the mortgage data, display the values and then call the pay function recursively with the updated mortgage. It sounded easy but I wasn't certain how to go about using a "local" variable in a function.  In the two parts of HTDP that I studied there was little discussion of the scope of bindings, though the local function was introduced. I had read somewhere that lexical scoping applied in Racket. So I tried out this simple code:

> (define a 1)
> (define (f) (define a 2) (displayln a))
> (displayln a)
1
> (f)
2
> (displayln a)

It turned out that it's easy to define a local binding in Racket. The code is at ex_1_10_making_a_table.rkt


However, I'm now puzzled as to why HTDP introduced the local function and didn't mention that defining a binding inside a function would result in it being local to the function.

Adding the code to display the table was very straightforward in the "practical" - ex_1_10_making_a table_2.rkt

The final step in the mortgage exercise is to eliminate the overpayment in the final month. This required the separation of the interest calculation and payment when working out the new mortgage balance each month. Then the monthly payment could be calculated as the minimum of the normal payment amount and the outstanding balance. This was straight forward in the "practical" version with an additional when expression.  (ex_1_11_mortgage_2.rkt).

The "HTDP" version required a couple of additional local bindings to get this done. (ex_1_11_mortgage.rkt).

To complete the introductory section on Numbers, lets compare the "practical" Python and Racket solutions. (This is my Python solution not that supplied by David Beazley).

Python:
# mortgage.py
#
# Exercise 1.11

principal = 500000.0
rate = 0.05
payment = 2684.11
total_paid = 0.0
number_payments = 0
extra_payment_start_month = 61
extra_payment_end_month = 108
extra_payment = 1000

while principal > 0:
    principal = principal * (1+rate/12)
    payment = min(payment, principal)
    principal = principal - payment
    number_payments += 1
    total_paid += payment
    if  number_payments >= extra_payment_start_month and \
        number_payments <= extra_payment_end_month:
        total_paid += extra_payment
        principal -= extra_payment 
    print(number_payments,
          round(total_paid, ndigits=2),
          round(principal, ndigits=2))
    
print('Total paid', round(total_paid, ndigits=2), end=' ')
print('in', number_payments, 'months')

Racket:
#lang racket

(define principal 500000.0)
(define rate 0.05)
(define payment 2684.11)
(define total-paid 0.0)
(define number-months 0)
(define extra-payment-start-month 61)
(define extra-payment-end-month 108)
(define extra-payment 1000)

(define (pay)
  (cond
    [(<= principal 0) total-paid]
    [else (set! number-months (add1 number-months))
          (set! principal (* principal (+ 1 (/ rate 12))))
          (set! payment (min payment principal))
          (set! principal (- principal payment))
          (set! total-paid (+ total-paid payment))
          (when (and (>= number-months extra-payment-start-month)
                     (<= number-months extra-payment-end-month))
            (set! total-paid (+ total-paid extra-payment))
            (set! principal (- principal extra-payment)))
          (display number-months)
          (display " ")
          (display total-paid)
          (display " ")
          (displayln principal)
          (pay)]))

(display "Total paid ")
(display (pay))
(display " in ")
(display number-months)

(displayln " months.")

The biggest conceptual difference to me is the need to employ a recursive function in Racket to repeat the calculation. The other noticeable difference at this stage is that the most people would consider the Python to be easier to read. (Though the need to use a continuation mark suggests frustration ahead for the unaware.)

Next up 1.4 Strings.

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.


Thursday, 2 July 2020

(practical-python->racket exercise 1.7 mortgage)

The first exercise is to calculate the total payments taken to pay off a 30-year fixed rate mortgage. David Beazley provides an initial solution to get his students started.


I started to think through how best to convert David's example into Racket. Almost without thinking, I fell back on the techniques covered in the first parts of How To Design Programs (HTDP). I designed a structure to hold the data and then wrote a recursive function to process it. (How else to replicate a while loop in Racket?) I added a couple of simple tests to check it was working. The program gives the same result as its Python equivalent but with its structure and function definitions, it lacks the immediacy of it:

#lang racket
(require test-engine/racket-tests)

; data definitions
(define-struct mortgage 
  [balance rate payment num-payments total-paid])

; data
(define daves-mortgage
  (make-mortgage 500000.00 0.05 2684.11 0.00 0.00))

; functions
(check-within (apply-interest 100 1.20) 110.0 1e-5)
(define (apply-interest balance rate)
  (* balance (add1 (/ rate 12))))

(check-within (pay daves-mortgage) 966279.6 1e-5)
(define (pay mortgage)
  (cond
    [(<= (mortgage-balance mortgage) 0) 
     (mortgage-total-paid mortgage)]
    [else (pay (make-mortgage
                (- (apply-interest
                    (mortgage-balance mortgage)
                    (mortgage-rate mortgage))      
                (mortgage-payment mortgage))
                (mortgage-rate mortgage)
                (mortgage-payment mortgage)
                (add1
                 (mortgage-num-payments mortgage))
                (+ (mortgage-total-paid mortgage)
                (mortgage-payment mortgage))))]))

(test)

; The "program"
(display "Total paid ")
(displayln (pay daves-mortgage))

So I set about trying to better emulate the Python version. In my first attempt, I passed indvidual values to the recursive function instead of a structure. It looked a little more like the Python version and was roughly half the length of the "HTDP" attempt (in terms of lines of code). But it still didn't feel very "practical".

The only way I could think of to make the code look more like the Python was to use "global, mutable variables" (in the same way that the Python does). In the part of HTDP that I had studied, there was never any mention of changing data, everything was immutable. I had somewhere seen "set" used in Racket code so I looked it up in the Racket Reference and did my worst. The code does look much more more like the Python but must rank as some of the worst Racket code ever written:

#lang racket

(define principal 500000.0)
(define rate 0.05)
(define payment 2684.11)
(define total_paid 0.0)

(define (pay)
  (cond
    [(<= principal 0) total_paid]
    [else (set! principal 
                (- (* principal (+ 1 (/ rate 12)))
                   payment))
          (set! total_paid (+ total_paid payment))
          (pay)]))

(display "Total paid ")
(displayln (pay))

Wednesday, 1 July 2020

(practical-python->racket 1.3 numbers)

The first challenge that I faced in translating the examples of Practical Python Programming - 1.3 Numbers was the differences in the number type systems between Python and Racket.

Python has a flat number type system with four types: booleans, integers, floating point and complex (imaginary numbers).

Racket has a heirarchical number type system. There are two main branches in the heirarchy, exact and inexact. This is a somewhat simplified view of the Racket number type hierarchy:
    exact
      integer      e.g. 10 - like a Python integer
      rational     e.g. 1/2
      complex    e.g. 1 + 2i
    inexact
      real          e.g. 2.0 - like a Python floating point
      complex    e.g. 2.1 + 3.3i

Racket also has two specialists number types, flonum (floating point) and fixnum (integer), that are used when there is a need for improved performance. These have their own maths operators. (I haven't looked into them any further at this stage.)

When "translating" the Python code, I have equated its integer with Racket's exact and its floating point with Racket's inexact.

The second came from Python's boolean type. It's a very raw C-language type with very few barriers to how a programmer can use it. For all I know, Racket's boolean type may similarly be implemented using integers. However, as far as the Racket programmer is concerned, it supports only two values: true and false.

I didn't want my script to just raise an error and stop when I tried to add a number to a boolean. After searching the docs and a little trial and error, I worked out how to trap an error:

   (racket '(define c 4))
   (racket "(+ c true)")
   (expect "Contract violation")
   (with-handlers ([exn:fail:contract?
                 (lambda (err) 
                  (displayln "Contract Violation"))])
                 (+ c true))

The third was tame in comparison, working out how to convert an inexact float to an exact integer. I came up with using: 

   (inexact->exact (floor my-float-value))

Take a look at the numbers.rkt script, then run it either in Dr Racket or the Racket repl. Do the result make sense?

Tuesday, 30 June 2020

(practical-python->racket approach)

Superficially, it seemed logical to start at the beginning. But upon reading the first few pages, it soon became clear to me that attempting to "translate" them requires a deeper knowledge of Racket than I have today. I thought it best to start with some easier material. So, I started with the introductory material about numbers, strings and lists that was easier to translate. I'll come back to the start later.

Each section of the course includes examples and exercises. My approach is to write a single Racket script which includes all the examples. (Is it even correct to refer to a short Racket program as a script?). I write a separate Racket program for each of the exercises. I'll write any notes I might have in this blog. I'll store the Racket programs in GitHub.

After a few false starts I managed to work out how to get the Racket that I've written to run in both Dr Racket and the Racket repl. I had written a few short Racket functions to reduce the amount of typing to complete the example scripts.

For example, instead of writing (displayln "Python: a = True") I can write (python "a = True"). It's basic text substitution. 

The function that I use to "expand" (racket value) is a little more sophisticated / complicated depending on you point of view.

(define-namespace-anchor anchor)
(define ns (namespace-anchor->namespace anchor))
(define (racket rkt)
  (cond
    [(list? rkt) (display "Racket: ")
                 (writeln rkt)
                 (eval rkt ns)]
    [(string? rkt) (displayln (string-append "Racket: " rkt))]
    [else          (displayln "Racket: Oops")])) 

The racket function will display its arguments and also evaluate the argument if it is a list. 

What took the time to figure this out was that you don't need to provide the namespace to the eval function when you run code in the repl unless you  specify #lang racket. It seems that Dr Racket insist on you specifying a language. So the code wouldn't run in Dr Racket.

I couldn't see a quick solution staring at me from the pages of the documentation. As I was really just performing text substitution, I thought I'd be better off writing a macro.

It took me number of attempts but I did eventually manage to get a macro to do pretty much the same thing. The issue that I came across was that I couldn't work out how to just expand the code with the macro and not evaluate it. So when I ran the script, all the macros were run before the rest of the code and the output was not in the order I wanted. (I guess I could have translated all my "expander" function to macros but I'll leave that for another time).

I went back to the docs and found that what I need to get my racket function working was to create and provide it a namespace. I first used make-base-namespace to create the namespace. I later found that I needed more modules than provided in racket/base to emulate the Python examples. Section 15.1 eval in The Racket Guide had a simple example of creating a namespace based on the "language" being used.

On to the first translation 1.3 Numbers.



Friday, 26 June 2020

(practical-python->racket introduction)

Recently, renowned Python expert David Beazley generously open-sourced his Practical Python Programming course. My Python skills are steadily improving through consistent use and watching talks and tutorials on YouTube. I've learnt a lot from David's talks and tutorials.

Sometimes I feel that my understanding of languages can be more theoretical than practical. I spent too much time learning and not enough time applying my knowledge. Practical Python Programming sounded exactly what I needed. I set out dutifully entering the examples into Python and doing the exercises. It was helpful. I even learnt that the Chicago Transit Authority #22 bus doesn't run at night.

What is Practical Programming though? Well to me, it's writing programs, short or long, to get things done quickly and efficiently. Effectively, it's turning a computer into a personal productivity tool. My current practical programming project helps me analyse companies. It is putting knowledge to use. 

I was mid-way through Chapter 1 of Practical Python Programming when a sudden thought broke my concentration. "This is just the type of material that would help me move forward with Racket. Hmmm, perhaps I should try coding the examples and exercises in Racket?"

So I tried out the introduction to Lists. I found I was able to "translate" the examples to Racket with some difficulty and quite a bit of "Doc Diving". During the process I expanded my knowledge of Racket and reinforced what I already knew. It seemed like a good idea to continue and get as far through the course as I could. I'll try to write about my experience in doing so in this blog as it helps me to remember what I've learnt.

I contacted David Beazley and he was happy for me to blog about my efforts to "translate" his Python to Racket. Though this is not in anyway his endorsement of the contents.

Another word of warning, this is very much a pseudo-mechanical translation. It's turning idiomatic Python into Racket. The code will certainly not be idiomatic Racket code. It could well turn out to be idiotic Racket code. Let's see.

You can read about my approach or go straight to the first section.




Monday, 22 June 2020

Learning Racket

I decided to try to learn Racket. Why?

It's not directly relevant to my current programming in JavaScript, Lua, Python and Rebol. Most of my programming work has been, is, and probably will be, run of the mill application software development. Since I started working as a programmer, languages such as Lisp, Forth and Prolog have always held an element of intrigue for me. They are different from the languages that I use.

Rebol is said to have both Lisp and Forth in its genes. But somehow, it doesn't hold the same level of intrigue. Perhaps its because the majority of people in the Rebol community were intent on using Rebol rather than discussing its design and implementation. The focus was far more on what you could do with Rebol than what you could do to Rebol. It could also be that, to quote a friend, "I wrote Rebol code the same way I wrote COBOL".  On the other hand, it could be that I have reached a reasonable level of fluency and the intrigue has faded during the process.

I didn't start out to learn Racket because I found it intriguing though. I had something else in mind. Functional programming is a hot topic these days (at least in the circles I'm connected with). It is the "only" answer to make use of the ever increasing number of cores in CPUs according to many of its proponents. Object oriented programming is frowned upon in the same circles these days. I use functions in my programs. I use objects in my programs. 

However, I feel that I have a superficial understanding of functional programming. I've taken a quick look at Erlang, studied books on functional programming in JavaScript and watched YouTube videos promoting functional programming in Python. I have an equally superficial understanding of object-oriented programming. I've half-heartedly studied Java in the past. I have learned a little Ruby and dipped in to the world of "proper" object-oriented programming. 

I believe that I would be a better programmer if I was more fluent in both functional programming and object-oriented programming metaphors. I decided to try to learn a functional style programming language and, after that, to properly try object-oriented programming. 

I've even identified two simple projects that I could use as learning vehicles. I know from experience, that I will only reach the level of fluency in a style of programming when I can use it productively by writing useful code in it.

It was easy for me to choose to use Ruby as a medium for object-oriented programming. The choice was not so easy when it came to functional programming.

I was encouraged to learn Elixir. It seems to have taken over some of people's previous enthusiasm for Ruby. People mentioned "SICP" in glowing terms insinuating that it is the seminal functional programming text. You can follow SICP using Racket. In the past, I had heard favourably of Racket. I took a look. It is very professional presented with a lot of documentation. It is easy to install and get started. 

I decided to work through "How To Design Programs" or HTDP as it appears to be snappily known. I chose the word work carefully. I completed around 40 percent of HTDP and did about 90 percent of the 240 exercises I have so far encountred  I probably spent an hour a day studying HTDP. Sometimes it felt a little like "Wax on, wax off" as the exercises felt a little repetitious to me.

It was taking too long to hold my attention, so I switched to The Racket Guide. I made faster progress but also soon realised that I'll need to complete reading most of the guide before I can start writing Racket programs.

At the moment, I still feel that I have a way to go before I can start on even a small project in Racket to start building some actual fluency. I'm not sure that I have the stamina to finish The Racket Guide as an academic exercise.

Thankfully, I have stumbled across another approach which has boosted my enthusiasm which you can read about at (practical-python->racket introduction).