ECS 15 -- Fall 1997 -- © Nancy E. Reed, 1997

Laboratory 9 Notes
Creating a Contact List Database

Handouts:

Readings:

Creating the Scheme Procedures for a Contact List Database

This laboratory exercise is different from the previous ones in that a "framework" or "skeleton" of the procedures you need to write is not provided. You will have a chance to work out the details of the algorithms and code for the required functions for a contact list using association lists.

Writing these small procedures makes use of the program development process covered earlier. Refer to that handout to help with the steps in the process of creating your programs.

During the demonstration in class today, we will collaboratively develop some of the specifications, algorithms, and code, for the functions that work on your contact list. The rest is up to you. Get an early start for best results.

Below we will develop the procedures for a similar problem - creating a banking database.

let* - a "somewhat new" function

You will be using the Scheme functions you already know from the previous labs for this lab. The only somewhat new function is let*. The syntax for let* is identical to that of let. The difference is that let* forces a sequential evaluation of the local variables and can therefore be used when the value of one local variable depends on the value(s) of other local variable(s).

When using let, the order of variable binding is not guaranteed to be sequential (the interpreter/compiler can perform them in any order chosen). let* can be used everywhere let can be used, but it makes the interpreter or compiler do a bit more work to guarantee the order of evaluation.

An example of the use of let* can be found in the Scheme code for the sample final exam in the change-each-value procedure. Look at the difference between this procedure and the others that use let (example: print-all-category) in the file valuable.scm.

Syntax of let*:

(let* (( < variable >  < value > ) + ; 1 or more variables and values
      )
      < statements > )

There is also a do* function. Do* does exactly what do does, with the exception that the (local) loop variables are guaranteed to be bound (assigned values) sequentially, in the same way that variables are bound with let*, as compared to let.

Creating a Banking database using association lists.

This example shows the design and implementation of procedures for a database of bank accounts. We will create the basic procedures necessary create the database and to manipulate the data in the database. Your bank account database should have the following structure:

	(
		(ID-number  Balance  Name  Address  Phone-Number)
		(ID-number  Balance  Name  Address  Phone-Number)
		(ID-number  Balance  Name  Address  Phone-Number)
		...
	)

This structure is an association list containing an arbitrary number of sub-lists, where each sub- list contains information about one bank account. Each sub-list is composed of the following items:

  1. ID number, represented as a string. This will be used as the key to retrieve a sub-list. For example, this might be "4517".
  2. Balance, represented as a number. The current balance in the bank account, in dollars. For example, this may be 56.00 if the account currently holds fifty-six dollars and no cents. You should not use quotations marks around the balance. The balance should not be represented as a string, but rather as a number since you will need to perform algebraic computations with the balance.
  3. Name, represented as a string. This is the name of the person with this account. For example, this might be "Fred Flintstone".
  4. Address, represented as a string. This is the street and city where the person with the account lives. For example, this might be "1 Rocky Wy., Bedrock".
  5. Phone-Number, represented as a string. This is the telephone number of the person with the account. For example, this might be "916-441-4121".
The balance, name, address, and phone-number will be retrieved based on the ID number, just like the family name was retrieved based on the family relationship in laboratory #8. As an example, your bank account A-list database might look like the following:
(
   ("2141"  100.00  "Fred Flintstone"  "1 Rocky Wy., Bedrock"  "244-412-3912")
   ("3988"  144.12  "Betty Rubble"  "2 Graphite Ln., Bedrock"  "244-412-3114")
   ("1211"  981.00  "Greg Granite"  "3 Geode St., Red Rock"  "244-412-3912")
)

In this example, the database contains three sub-lists. The first has data for Fred Flintstone. He has $100 in his account, lives at 1 Rocky Way in Bedrock, has a phone number of 244-412-3912, and his ID number is 2141. Similarly, Betty has $144.12, lives at 2 Graphite Lane in Bedrock, has a phone number of 244-412-3114, and has a ID number of 3988.

To manipulate the bank account database, you will need to create the bank data structure and write the following functions.

  1. Initialize the global variable, *Bank*, to be an empty list.
  2. Create an Add-Account-Silent procedure which adds a ID number, starting balance, name, address, and phone number to the A-List *Bank*.
  3. Create a Get-Account procedure which takes a ID number as input, and displays the information in the corresponding account (i.e., the ID number, balance, name, address, and phone number).
  4. Create a Display-Accounts procedure which displays the ID number, balance, name, address, and phone number of everyone in *Bank*.
  5. Create a Change-Name procedure which takes as input a ID number and a new name, and replaces the old name in the corresponding account with the new name.
  6. Create a Make-Deposit procedure which takes as input a ID number and a deposit amount, and changes the corresponding account balance to contain the sum of the old balance and the deposit amount.
  7. Create a Make-Withdrawal procedure which takes as input a ID number and a withdrawal amount, and changes the corresponding account balance to be the old balance minus the withdrawal amount if the old balance is greater than or equal to the withdrawal amount. If there are not sufficient funds (i.e., the withdrawal amount is more than the old balance) then an error message should be displayed and the withdrawal should not be made.

The bank data structure

Create the global variable *bank* and initialize it to the empty list with:

(define *bank* (list))

The add-account-silent function

The description: The add-account-silent procedure adds a ID number, starting balance, name, address, and phone number to the A-List *Bank*.

Procedure name: add-account-silent
Arguments: (5) ID balance name address phone
Side Effects: add a new sublist to *bank* with the new information
Input/Output: none specified.
Result: none specified.

(define (add-account-silent ID balance name address phone)
  (set! *bank* 
        (cons (list ID balance name address phone) *bank*)))

The make-deposit procedure

;;;;;; The MAKE-DEPOSIT procedure example

; Description 
; make-deposit takes as input an ID number and a
; deposit amount, and changes the corresponding account balance to
; contain the sum of the old balance and the new amount.

; To start the definition, we need:

; Procedure: MAKE-DEPOSIT
; Arguments: ID deposit
; Input/Output: none specified
; Side Effects: none specified

; Pseudocode algorithm:

; get the current balance of the account (from the database)
; calculate the new balance by adding the current balance to the deposit amount
; save the new balance back to the database

; Code in Scheme
; We must start to define the function with its name & arguments:

; In Scheme syntax that is:
; (define (make-deposit id deposit)
;  ..... )
; The code for most of the functions is included below.

The Banking database functions in Scheme

;;;;;;;;;;;;;;;;; Creating a Banking Database
;  ECS15,  Nancy Reed

;  The form of the Association list for the bank 
;(
;   (ID-number Balance Name Address Phone-number)
;   (ID-number Balance Name Address Phone-number)
;   (ID-number Balance Name Address Phone-number)
; ......
; )
; ID-number -> string
; Balance -> number
; Name -> string
; Address -> string
; Phone-number -> string

;;;;;; Data structure necessary:
;; 1. Global variable *bank*

(define *bank* (list))

;; 2. add-account-silent procedure (arguments: ID, balance, name, address, phone)

(define (add-account-silent id balance name address phone)
  (set! *bank* (cons (list id balance name address phone) *bank*)))

; Some data to start with
(add-account-silent "2141" 100.00 "Fred Flintstone" "1 Rocky Wy., Bedrock"
        "244-412-3912")
(add-account-silent "3988" 944.12 "Betty Rubble" "2 Graphite Ln., Bedrock"
        "244-412-3114")
(add-account-silent "1242" 991.41 "Wilma Flintstone" "1 Rocky Wy., Bedrock"
        "244-412-3912")

;; 3. Get-account procedure (arguments: ID)

(define (get-account id)
  (assoc id *bank*))

;; 4. Display-accounts procedure (arguments: Alist-of-data)

(define (display-accounts accounts)
  (cond
    ((null? accounts)
     (display "End of accounts.")
     (newline))
    (else
      ; display info in the first sublist
      (let*
        ((sublist (car accounts))
         (id (car sublist))
         (balance (cadr sublist)) ; cadr = car cdr
         (name (caddr sublist))
         (address (cadddr sublist))
         (phone (car (cddddr sublist))) )
        (display         ; display in columns
          (string-append 
            id (make-string (- 10 (string-length id)) #\space)
            "$" (number->string balance) 
            (make-string (- 10 (string-length 
                                 (number->string balance))) #\space)
            name  (make-string (- 20 (string-length name)) #\space)
            address (make-string (- 25 (string-length address)) #\space)
            phone))
        (newline)
        ; recursive call on the rest of the list
        (display-accounts (cdr accounts))) ) ) )

;; 5. Change-name procedure (arguments: ID, new-name)

(define (change-name ID newname)
  (display "This function is left as an exercise for the reader") 
  )

;; 6. Make-deposit function (arguments: ID, deposit-amount)

(define (make-deposit id deposit)
  ; modify balance of account with id=ID so it is old balance + deposit
  (let*
    ((sublist (assoc id *bank*))
     (newbalance (+ deposit (cadr sublist))))
    (set-car! (cdr sublist) newbalance) ) )

; 7. Make-withdrawal function (arguments: ID, withdrawal-amount)
;  NOTE:  Make sure there is enough $, or else issue a warning message

(define (make-withdrawal id amount)
  (let*
      ((balance-list (cdr (assoc id *bank*)))
      (balance (car balance-list)))
    (cond
     ((> amount balance)
      (newline)
      (display "Error, not enough money in account."))
     (else
      (set-car! balance-list (- balance amount))))))

Go to the index of lectures for ECS15 - Fall 1997 .

Go to the homepage for ECS15 - Fall 1997 .

© Nancy E. Reed, 1997 -- nereed@ucdavis.edu