for
CSCI 1301: Great Ideas in Computer Science
(c) 1993 - 2007 John E. Howland, All Rights Reserved
Department of Computer Science
Trinity University
One Trinity Place
San Antonio, Texas 78212-7200
Internet: jhowland@ariel.cs.trinity.edu
This method involves a hierarchical or tree-like structure for a system as illustrated by the following diagram:

At the top level, we have that part of the system which deals with the overall system; a kind of system overview or main top-level module.
An alternate design metholodogy, Bottom-up design, starts with description of the lowest level system components together with description of how such components are assembled to form higher level system components. This design methodology continues until all levels of the system are connected in a hierarchical structure to form the entire system.
Top-down design is preferred because, at the beginning of an analysis and design cycle, it is usually not possible to know the lower level design details which are determined by a process of successive refinement.
We will attempt to illustrate this top-down methodology with an example. As with all of the topics covered so far in this course, we will model this system using the J programming notation. One might actually use some language other than J (such as Scheme or C) to implement a database system. However, the approach we use is valid since one might use J to implement a prototype system and then use the C programming language for the production system. This is an example of an important technique known as software prototyping. Just as an engineer always builds at least one prototype machine before giving the go-ahead to begin production of the machine, many software engineers also use this same technique. J is a particularly good language for prototyping as we shall soon see.
Since most J systems are already interactive systems, we can simplify our prototype design by using the J top-level as our prototype's top-level.
Similarly, we can use the J syntax for our data base command language. This means that we can use the J system's read-eval-print loop (the second level in our system diagram) as our prototype's second level and third level. It should now begin to be obvious why J is a good prototyping language for interactive systems. We are already down to the fourth level of our design and we have yet to begin to design or implement any programs!
Another aspect of this design method of building a system from the top down in distinct layers is that it is possible (and desirable) to attempt to make each layer of software independent from the layers above and below it. This involves design of some sort of abstract interface between the layers.
The most important benefit of design layers is that it should then be possible to change the software in one layer (provided the new version of that layer adhears to the same interface above and below) without having to change any other part of the software design.
This is a lofty design goal. In practice, it is often very difficult to achieve.
people =: ('howland' ; 'jack' ; 'computer science professor') ; ('clinton' ; 'bill' ; 'president usa') ; ('clinton' ; 'hillary' ; 'president usa') ; ('perot' ; 'ross' ; 'wanted to be president') ; < ('bush' ; 'george' ; 'used to be president')
Following
is a function which will lookup up a key in a database. In the following
definitions, we use the primitive J spelling for the words:
box =: < append =: , link =: ;In section 6.6.1 we defined a predicate, nullp, for empty lists as:
nullp =: (0 bond =) atop tallywhich we also use below.
lookup =: monad define
('name' ; 'database') =. y.
if. nullp database
do. ''
else. if. name match head head database
do. head database
else. lookup name ; < rest database
end.
end.
)
lookup 'clinton';<people
+-------+----+-------------+
|clinton|bill|president usa|
+-------+----+-------------+
lookup just finds the first match in the database. Most databases of any size will have multiple matches for a given key. Following is a function which will lookup all matches of a given key.
lookup_all =: monad define
('key' ; 'datalist') =. y.
if. nullp datalist
do. ''
else. if. key match head head datalist
do. (< rest head datalist) , lookup_all key ; < rest datalist
else. lookup_all key ; < rest datalist
end.
end.
)
lookup_all 'clinton' ; < people
+--------------------+-----------------------+
|+----+-------------+|+-------+-------------+|
||bill|president usa|||hillary|president usa||
|+----+-------------+|+-------+-------------+|
+--------------------+-----------------------+
Notice that by the way we have constructed the data associated with each key in the people database, that the result of using lookup-all is to produce a new database which might be used as the database for a lookup operation.
lookup 'hillary' ; < lookup_all 'clinton' ; < people ==> +-------+-------------+ |hillary|president usa| +-------+-------------+ lookup 'bill'; < lookup_all 'clinton' ; < people ==> +----+-------------+ |bill|president usa| +----+-------------+Next we consider the problem of adding items to an existing database. The result of this operation is a new database. Therefore to actually add an item to an existing database we need to re-bind the name of the existing database to be the result of add-data.
add_data =: monad define
('item_pair' ; 'datalist') =. y.
(< item_pair) , datalist
)
To
examine the add_data operation note:
people =: add_data ('howland';'glynne';'nail manufacturer');<people
0 from people ==>
+----------------------------------+
|+-------+------+-----------------+|
||howland|glynne|nail manufacturer||
|+-------+------+-----------------+|
+----------------------------------+
lookup_all 'howland' ; < people ==>
+--------------------------+---------------------------------+
|+------+-----------------+|+----+--------------------------+|
||glynne|nail manufacturer|||jack|computer science professor||
|+------+-----------------+|+----+--------------------------+|
+--------------------------+---------------------------------+
We
now address the problem of removing items from a database. As in the previous
database operations we form a new database which is a copy of the old database
less the item being removed.
remove_data =: monad define
('key' ; 'datalist') =. y.
if. nullp datalist
do. ''
else. if. key match head head datalist
do. rest datalist
else. (< head datalist) , remove_data key ; < rest datalist
end.
end.
)
To
examine the remove_data operation try:
people =: remove_data 'howland' ; <people lookup_all 'howland';<people ==> +---------------------------------+ |+----+--------------------------+| ||jack|computer science professor|| |+----+--------------------------+| +---------------------------------+
We need to be able to remove all items matching a given key.
remove_all_data =: monad define
('key' ; 'datalist') =. y.
if. nullp datalist
do. ''
else. if. key match head head datalist
do. remove_all_data key ; < rest datalist
else. (< head datalist) , remove_all_data key ; < rest datalist
end.
end.
)
To
examine the operation of remove_all_data, recall that
shape people ==> 5 lookup_all 'clinton';<people ==> +--------------------+-----------------------+ |+----+-------------+|+-------+-------------+| ||bill|president usa|||hillary|president usa|| |+----+-------------+|+-------+-------------+| +--------------------+-----------------------+ people =: remove_all_data 'clinton' ; < people lookup_all 'clinton' ; < people ==>Note that there are no longer any 'clinton' keys in the people database.
shape people ==> 3 0 from people ==> +-----------------------------------------+ |+-------+----+--------------------------+| ||howland|jack|computer science professor|| |+-------+----+--------------------------+| +-----------------------------------------+ 1 from people ==> +-----------------------------------+ |+-----+----+----------------------+| ||perot|ross|wanted to be president|| |+-----+----+----------------------+| +-----------------------------------+ 2 from people ==> +----------------------------------+ |+----+------+--------------------+| ||bush|george|used to be president|| |+----+------+--------------------+| +----------------------------------+
people_lookup =: monad def 'lookup y. ; < people'Similarly we can define:
people_all_looker =: monad def 'lookup_all y. ; < people'The behavior of these specialized operations is examined in the following expressions.
people_lookup'bush' ==> +----+------+--------------------+ |bush|george|used to be president| +----+------+--------------------+ people_lookup'clinton' ==> people_all_looker 'howland' ==> +---------------------------------+ |+----+--------------------------+| ||jack|computer science professor|| |+----+--------------------------+| +---------------------------------+
There are four utility verbs which are needed to construct two verbs, write_list and read_list which will allow J lists to be permenantly saved as files. Two of the four utility verbs (read and write) will not be fully explained at this time. We will still be able to make effective use of read and write even though we may not fully understand their J definitions. Their definitions are:
read =: monad def '1 !: 1 < y.' write =: dyad def 'x. 1 !: 2 < y.'J objects are stored in files as strings of characters. The dyad write requires a character list for its left input and a quoted filename for its right input; the character list is written to the indicated file. For example,
'Hi there' write 'junk'creates a file named junk containing the characters 'Hi there'. A file may only contain characters as data. The monad read requires a quoted filename as its right input; the indicated file is read into the J environment. For example:
read 'junk' ==> Hi thereJ lists may consist of arbitrary J items (numbers of various types, characters, functions, etc.). To write and read J lists to and from files it is necessary to convert these lists to and from character strings. Two utilities are available to do this, however, it should be noted that files created this way on one type of computer system (Unix) may not be readable on another type of computer system (Intel architecture). The utility functions are:
to_char =: 3 !: 1 to_internal =: 3 !: 2These verbs are used to define the following verbs which may be used to store and retrieve J objects (including lists) as files.
write_list =. dyad def '(to_char x.) write y.' read_list =. monad def 'to_internal read y.'
people write_list 'people.database'
people match read_list 'people.database' ==> 1Suppose we have the following database file, people.db such that:
open read_list 'people.db' ==> +-------+--------+--------------------------+ |konstam|patricia|newspaper writer | +-------+--------+--------------------------+ |konstam|aaron |computer science professor| +-------+--------+--------------------------+ |eggen |maury |computer science professor| +-------+--------+--------------------------+ |howland|jack |computer science professor| +-------+--------+--------------------------+ |howland|glynne |nail manufacturer | +-------+--------+--------------------------+ |clinton|bill |president usa | +-------+--------+--------------------------+ |clinton|hillary |first lady usa | +-------+--------+--------------------------+ |perot |ross |wanted to be president | +-------+--------+--------------------------+ |bush |george |used to be president | +-------+--------+--------------------------+
lookup_file =: monad define
('key' ; 'filename') =. y.
lookup key ; < read_list filename
)
lookup_file 'eggen' ; 'people.db' ==> +-----+-----+--------------------------+ |eggen|maury|computer science professor| +-----+-----+--------------------------+
lookup_all_file =: monad define
('key' ; 'filename') =. y.
lookup_all key ; < read_list filename
)
lookup_all_file 'clinton' ; 'people.db' ==> +--------------------+------------------------+ |+----+-------------+|+-------+--------------+| ||bill|president usa|||hillary|first lady usa|| |+----+-------------+|+-------+--------------+| +--------------------+------------------------+
add_data_file =: monad define
('item_pair' ; 'filename') =. y.
(add_data item_pair ; < read_list filename) write_list filename
)
tally read_list 'people.db' ==>
9
add_data_file ('pitts';'gerald';'computer science professor');'people.db'
tally read_list 'people.db' ==>
10
open read_list 'people.db' ==>
+-------+--------+--------------------------+
|pitts |gerald |computer science professor|
+-------+--------+--------------------------+
|konstam|patricia|newspaper writer |
+-------+--------+--------------------------+
|konstam|aaron |computer science professor|
+-------+--------+--------------------------+
|eggen |maury |computer science professor|
+-------+--------+--------------------------+
|howland|jack |computer science professor|
+-------+--------+--------------------------+
|howland|glynne |nail manufacturer |
+-------+--------+--------------------------+
|clinton|bill |president usa |
+-------+--------+--------------------------+
|clinton|hillary |first lady usa |
+-------+--------+--------------------------+
|perot |ross |wanted to be president |
+-------+--------+--------------------------+
|bush |george |used to be president |
+-------+--------+--------------------------+
people_file_looker =: monad def 'lookup_file y. ; ''people.db'''Notice that this definition has the special problem of requiring that a single quote appear inside a quoted definition. The way this is accomplished is to represent a single ' by ''.
people_file_looker 'howland' ==> +-------+----+--------------------------+ |howland|jack|computer science professor| +-------+----+--------------------------+Other people.db database file operations are easily defined. Such functions are left as an exercise for the reader.