Skip to content
/ HtDP Public

Solutions to some exercises from the Parts I and II of "How to Design Programs" book, Summer 2022

Notifications You must be signed in to change notification settings

gkorpal/HtDP

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

How to Design Programs, 2nd edition

I read the Parts I and II of the book. It involves working with Beginning Student Language (BSL) in DrRacket.

htdp htdp2

These recepies are similar to the one given in How to Solve It by Polya:

htsi

Therefore, according to the book, programs are collections of definitions: structure type definitions, data definitions, constant definitions, and function definitions. To guide the division of labor among functions, the following rough guidelines are available:

  • (chapter 3) Design one function per task. Formulate auxiliary function definitions for every dependency between quantities in the problem.
  • (chapter 11) Design one template per data definition. Formulate auxiliary function definitions when one data definition points to a second data definition.
  • (chapter 3 and chapter 11) Maintain a wish list of function headers that must be designed to complete a program. Before adding a function to the wish list, check whether something like the function already exists in the programming language’s library or whether something similar is already on the wish list.
  • And don’t forget tests.

Writing down complete function headers ensures that you can test those portions of the programs that you have finished, which is useful even though many tests will fail. Of course, when the wish list is empty, all tests should pass and all functions should be covered by tests.

For example, consider the following structurally recursive function that implements insertion sort in BSL+:

; List-of-numbers -> List-of-numbers
; produces a sorted version of l
(check-expect (sort< (list 5 2 4 6 1 3)) (list 1 2 3 4 5 6))
(define (sort< l)
  (cond
    [(empty? l) '()]
    [(cons? l) (insert (first l) (sort< (rest l)))]))
 
; Number List-of-numbers -> List-of-numbers
; inserts n into the sorted list of numbers l
(check-expect (insert 4 (list 1 3 6)) (list 1 3 4 6))
(define (insert n l)
  (cond
    [(empty? l) (cons n '())]
    [else (if (<= n (first l))
              (cons n l)
              (cons (first l) (insert n (rest l))))]))

This is a pure recursive form (functional/declarative programming) of the usual iterative form (procedural/imperative programming), we see in C:

struct LIST * SortList1(struct LIST * pList) 
{
    // zero or one element in list
    if (pList == NULL || pList->pNext == NULL)
        return pList;
    // head is the first element of resulting sorted list
    struct LIST * head = NULL;
    while (pList != NULL) {
        struct LIST * current = pList;
        pList = pList->pNext;
        if (head == NULL || current->iValue < head->iValue) {
            // insert into the head of the sorted list
            // or as the first element into an empty sorted list
            current->pNext = head;
            head = current;
        } else {
            // insert current element into proper position in non-empty sorted list
            struct LIST * p = head;
            while (p != NULL) {
                if (p->pNext == NULL || // last element of the sorted list
                    current->iValue < p->pNext->iValue) // middle of the list
                {
                    // insert into middle of the sorted list or as the last element
                    current->pNext = p->pNext;
                    p->pNext = current;
                    break; // done
                }
                p = p->pNext;
            }
        }
    }
    return head;
}

Note that, in HtDP we usually work with lists, but it does have arrays/vectors like seen in C.

On the other hand, quick-sort is an example of generative recursion, based on divide-and-conquer instead of "Design by Composition." Here is its implemention in ISL+:

; [List-of Number] -> [List-of Number]
; produces a sorted version of alon
; assume the numbers are all distinct 
; combines the two sorted lists and the pivot in the proper order
; first all those items smaller than pivot, then pivot, and finally all those that are larger. 
(define (quick-sort< alon)
  (cond
    [(empty? alon) '()]
    [else (local ((define pivot (first alon)))
            (append (quick-sort< (smallers alon pivot))
                    (list pivot)
                    (quick-sort< (largers alon pivot))))]))
 
; [List-of Number] Number -> [List-of Number]
; the list of items larger than the pivot
(define (largers alon n)
  (cond
    [(empty? alon) '()]
    [else (if (> (first alon) n)
              (cons (first alon) (largers (rest alon) n))
              (largers (rest alon) n))]))
 
; [List-of Number] Number -> [List-of Number]
; the list of items smaller than the pivot
(define (smallers alon n)
  (cond
    [(empty? alon) '()]
    [else (if (< (first alon) n)
              (cons (first alon) (smallers (rest alon) n))
              (smallers (rest alon) n))]))

Note that this implementation is for a list instead of an array, hence is based on the very early versions of quicksort in which the leftmost element of the partition is chosen as the pivot element. Unfortunately, this causes worst-case behavior on already sorted arrays, which is a rather common use-case.

For more information, I would recommend reading Beautiful Racket by Matthew Butterick.

Platform: Fedora Linux 36 (Workstation Edition) with GNOME Wayland

DrRacket Installation:

$ sudo ./racket-8.5-x86_64-linux-cs.sh
This program will extract and install Racket v8.5.

Note: the required diskspace for this installation is 666M.

Do you want a Unix-style distribution?
  In this distribution mode files go into different directories according
  to Unix conventions.  A "racket-uninstall" script will be generated
  to be used when you want to remove the installation.  If you say 'no',
  the whole Racket directory is kept in a single installation directory
  (movable and erasable), possibly with external links into it -- this is
  often more convenient, especially if you want to install multiple
  versions or keep it in your home directory.
Enter yes/no (default: no) > yes

Where do you want to base your installation of Racket v8.5?
  (If you've done such an installation in the past, either
   enter the same directory, or run 'racket-uninstall' manually.)
  1 - /usr/... [default]
  2 - /usr/local/...
  3 - ~/... (/root/...)
  4 - ./... (here)
  Or enter a different directory prefix to install in.
> 1

Target Directories:
  [e] Executables      /usr/bin (exists)
  [o] Libraries        /usr/lib/racket (will be created)
  [s] Shared files     /usr/share/racket (will be created)
  [c] Configuration    /usr/etc/racket (will be created)
  [d] Documentation    /usr/share/racket/doc (will be created)
  [a] .desktop files   /usr/share/applications (exists)
  [m] Man Pages        /usr/share/man (exists)
  [l] C Libraries      /usr/lib (exists)
  [h] C headers        /usr/include/racket (will be created)
  [z] Compiled at lib? yes
Enter a letter to change an entry, or enter to continue.
> 

Checking the integrity of the binary archive... ok.
Unpacking into "/usr/racket-tmp-install" (Ctrl+C to abort)...
Done.
Moving bin -> /usr/bin
Moving collects -> /usr/share/racket/collects
Moving share/pkgs -> /usr/share/racket/pkgs
Moving doc -> /usr/share/racket/doc
Moving lib -> /usr/lib/racket
Moving include -> /usr/include/racket
Moving share/applications -> /usr/share/applications
Moving share -> /usr/share/racket
Moving etc -> /usr/etc/racket
Moving man -> /usr/share/man
Moving README -> /usr/share/racket/doc/README
Writing uninstaller at: /usr/bin/racket-uninstall...
Rewriting configuration file at: /usr/etc/racket/config.rktd...
Moving "compiled" in /usr/share/racket/collects to /usr/lib/racket/compiled/usr/share/racket/collects
Moving "compiled" in /usr/share/racket/pkgs to /usr/lib/racket/compiled/usr/share/racket/pkgs
Rewriting configuration file at: /usr/etc/racket/config.rktd...

Installation complete.
$ drracket

drracket

About

Solutions to some exercises from the Parts I and II of "How to Design Programs" book, Summer 2022

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages