TEACH DIARY Riccardo Poli Feb 1995 Revised Sep 1997 USING THE POP-11 DATABASE TO IMPLEMENT AN ELECTRONIC DIARY This is the first marked exercise for SEM1A9. It includes two phases. In the first phase you will revise what you have learnt on the pattern matcher and the database. This part is not assessed but you need to understand the concepts recalled, before you move on to the second part. You can ask for help from the demonstrators while you go through the revision examples. In the second phase, you will use what you have learnt to implement an electronic diary. The marks awarded (up to a maximum of 10) will depend on how far you have gone in the exercise by the end of the workshop. During this phase you cannot ask for help from the demonstrators (unless you have questions of general interest not directly related to the assignment) nor from other students (this might be considered plagiarism). CONTENTS - (Use g to access required sections) -- Prerequisites -- Objectives -- Quick revision of the pattern matcher -- -- Example 1 -- -- Example 2 -- -- Example 3 -- -- Example 4 -- -- Example 5 -- -- Example 6 -- -- Example 7 -- -- Example 8 -- -- Example 9 -- -- Example 10: A toy Eliza-like application -- -- Example 11: Another toy Eliza-like application -- Quick revision of the database -- -- ADD procedure -- -- -- Example 12 -- -- -- Example 13 -- -- PRESENT procedure -- -- FOREACH-DO-ENDFOREACH -- -- -- Example 14 -- -- -- Example 15 -- -- FLUSH procedure -- -- A Toy Eliza based on the database -- The assignment -- -- add_appointment() -- -- cancel_appointment() -- -- appointments() -- -- search_appointments() -- -- Improvements -- Suggestions for the implementation -- Further reading -- Prerequisites ------------------------------------------------------ It is assumed that you are familiar with the use of the editor for creating and testing procedures (TEACH VEDPOP, TEACH VEDPROC, TEACH VEDNOTES). You should be familiar with techniques for defining procedures, the use of variables and the pattern matcher, and the use of conditionals. Revision TEACH files are: TEACH DEFINE, TEACH VARS, TEACH MATCHES, TEACH DATABASE gives a more detailed introduction to the Pop-11 database. You will also need to know how to construct multi-branch conditionals as explained in HELP IF. -- Objectives --------------------------------------------------------- This teach file has two objectives. The first objective is to teach you how to produce a "package" of procedures, using the Pop-11 database, to solve a simple problem (implementing an electronic diary in which you can add, search, delete appointments). The second objective is to assess your current fluency with the language and your ability to solve programming problems by dividing them into sub-problems which can be solved more easily. -- Quick revision of the pattern matcher ------------------------------ The MATCHES operator can be used to check if a list matches (i.e. has a structure which is compatible with) a pattern (another list in which special symbols like =, ==, ?, ?? can be used to specify the structure of a class of lists). See HELP *MATCHES or TEACH *MATCHES for more details. In the following, several examples of use of the pattern matchers are given. They are also present in your lecture notes. -- -- Example 1 ------------------------------------------------------ [a b c] matches [a b c] => The result of compiling the previous line is: ** -- -- Example 2 ------------------------------------------------------ [x b y] matches [= b =] => The result of compiling the previous line is: ** -- -- Example 3 ------------------------------------------------------ [[k1 k2 k3] b y] matches [= b =] => The result of compiling the previous line is: ** -- -- Example 4 ------------------------------------------------------ [x b y] matches [= B =] => The result of compiling the previous line is: ** -- -- Example 5 ------------------------------------------------------ [a b c] matches [a ==] => The result of compiling the previous line is: ** -- -- Example 6 ------------------------------------------------------ [x a b c y] matches [x == y] => The result of compiling the previous line is: ** -- -- Example 7 ------------------------------------------------------ vars l; [A b c] matches [?l b c] => l => The result of compiling the previous lines is: ** ** A -- -- Example 8 ------------------------------------------------------ [x a b c y] matches [x ??l y] => l => The result of compiling the previous lines is: ** ** [a b c] -- -- Example 9 ------------------------------------------------------ Local variables can be used in patterns ONLY if the patterns are preceded by an exclamation mark "!". For example: lvars l; [x a b c y] matches ![x ??l y] => l => The result of compiling the previous lines is: ** ** [a b c] -- -- Example 10: A toy Eliza-like application ------------------------ readline() -> x; if x matches [== my name is ??l] then [Hello ^^l !] ==> endif The result of compiling the previous lines with the following input: ? Hello, my name is Billy The Kid is ** [Hello Billy The Kid !] While with the following input: ? Hi boy, my name is Ilop Odraccir is ** [Hello Ilop Odraccir !] -- -- Example 11: Another toy Eliza-like application ----------------- vars x, y; readline() -> x; if x matches [== father ==] or x matches [== mother ==] then [Tell me more about your family] => elseif x matches [ == I am ??y] then [Did you come here because you are ^^y?] => else [Pardon?] => endif; Compiling the previous lines and giving the following input: ? My mother is very fat gives ** [Tell me more about your family] Here are three more runs: ? I am very unhappy ** [Did you come here because you are very unhappy ?] ? I am very fat ** [Did you come here because you are very fat ?] ? you are very fat ** [Pardon ?] -- Quick revision of the database --------------------------------------- The Pop-11 database is a variable called "database" containing a list of items. Initially the content of such a variable is just the empty list [], as can be easily seen by compiling the following line: database ==> Anything can be assigned to the database, as it is a normal variable. For example, compiling the lines: [[something]] -> database; database ==> gives as output: ** [[something]] This method of manipulating the database is, in general, only used do clear it, with the following command: [] -> database; Usually the database is manipulated by special procedures. They are described in you lecture notes. They are also revised in the following. -- -- ADD procedure ----------------------------------------------------- Here are some examples on how to use the procedure ADD to add information to the database. -- -- -- Example 12 ------------------------------------------------------ add([this is a thing I want to remember]); database ==> The result of compiling the previous lines is: ** [[this is a thing I want to remember]] -- -- -- Example 13 ----------------------------------------------------- The variable "it" will remember the last item in the database that has been accessed (added, deleted, retrieved, etc). add([this is another important thing]); database ==> it => After Example 12 has been run, the result of compiling the previous lines is: ** [[this is another important thing] [this is a thing I want to remember]] ** [this is another important thing] -- -- PRESENT procedure ----------------------------------------------- The PRESENT procedure can be used to check if a piece of information (a fact) is present in the database. As it is based on the pattern matcher, PRESENT allows complex searches to be performed. present([== important ==]) => it => After Example 12 and 13 have been run, the result of compiling the previous lines is: ** ** [this is another important thing] -- -- FOREACH-DO-ENDFOREACH ------------------------------------------ This construct allows you to perform some computation on each item of the database that matches a given pattern. Here are some examples. -- -- -- Example 14 -------------------------------------------------- foreach [== thing ==] do it => endforeach; The result of compiling the previous lines is: ** [this is another important thing] ** [this is a thing I want to remember] -- -- -- Example 15 -------------------------------------------------- foreach [this is ??x] do x => endforeach; The result of compiling the previous lines is: ** [another important thing] ** [a thing I want to remember] -- -- FLUSH procedure ----------------------------------------------- This is a procedure to delete a complete set of items from the database. All the items matching a given pattern are deleted. Here is an example: flush([== important ==]); database ==> The result of compiling the previous lines is: ** [[this is a thing I want to remember]] -- -- A Toy Eliza based on the database ----------------------------- [] -> database; add([father 'Tell me more about your family']); add([mother 'Tell me more about your family']); add([problem 'Is this the reason why you came here?']); define eliza(); lvars sentence, topic, reply, word; repeat readline() -> sentence; foreach ![?topic ?reply] do for word in sentence do if word == topic then npr(reply); quitloop(2); endif endfor endforeach; endrepeat; enddefine; eliza(); The result of compiling the previous lines is: ? I have a problem Is this the reason why you came here? ? yes, my mother is very fat Tell me more about your family -- The assignment ----------------------------------------------------- By using what you have learnt on Pop-11 (in particular on procedures, loops, conditionals, the pattern matcher and the database), try and write a set of procedures that implement an electronic diary. Do this in a file called diary.p in your home directory. Save this file at the end of the workshop and make sure that it is readable (this will allow us to check it later, for marking). Do not modify that file until you get your marks. Before the end of the workshop or when you have completed the exercise ask a demonstrator to check what you have done. The demonstrator will fill a form which will later help in the assessment of your work. Here are some suggestions on procedures you might want to write to implement the electronic diary. -- -- add_appointment() ---------------------------------------------- A procedure to add an appointment to the diary. It could have the following form: define add_appointment( day, time, what ) -> can_be_added; .... enddefine; Such a procedure would receive as input the day and time of the appointment and a list (what) describing the item to be added to the diary. A possible call could be: add_appointment( [March 2], [10 : 30 am], [Meeting with Eliza] ) If the diary entry for March 2, at 10:30am is free, the procedure should return to signal that the appointment has been fixed. Otherwise the procedure should return . Each appointment should be stored in the Pop-11 database as a single entry, i.e. as a compound fact, maybe represented as a list including three lists: one for the day, one for the time and one for the description of the appointment. For example, each entry could be something like: [[March 2] [10 : 30 am] [Meeting with Eliza]] The procedure add_appointment() should first check the presence in the database of another appointment having the same date and time. If this is the case it should return and should not add the appointment to the database. NOTE: the spaces between "10", the colon ":" and "30" are important. As ":" can be used to express numbers in a different base (e.g. in binary or octal), if the spaces are absent, Pop-11 will interpret 10:30 as the number 30 in base 10. Try compiling the following line: [10:30am] => -- -- cancel_appointment() ------------------------------------------- A procedure to cancel an appointment from the diary. It could have the following form: define cancel_appointment( day, time ); .... enddefine; Such a procedure would receive as input the day and time of the appointment. A possible call could be: cancel_appointment( [March 2], [10 : 30 am] ) If an appointment is present in the diary for March 2, at 10:30am this call should simply cancel such an appointment. If no appointment is present for that date, cancel_appointment() should simply do nothing. If each appointments is stored in the Pop-11 database as a single entry, the procedure cancel_appointment() should first build an appropriate pattern to match such an entry and then remove the entry using the procedure flush() or remove(). -- -- appointments() ------------------------------------------------- A procedure that returns a list of the appointments for a given day. It could have the following form: define appointments( day ) -> appointments; .... enddefine; Such a procedure would receive as input a day and should return a list of the appointment for such a day. A possible call could be: appointments( [March 2] ) If appointments are present in the diary for March 2 this call would return a list of such appointments such as: [ [[March 2] [9 : 00 am] [Do assignment]] [[March 2] [10 : 30 am][Meeting with Eliza]] ] The procedure appointments() should first build an appropriate pattern to match the database entries (the appointments) relative to the given day and then build a list of the matching entries, maybe using the foreach looping construct. -- -- search_appointments() ------------------------------------------ A more sophisticated procedure to find appointments in the diary. It could have the following form: define search_appointments( day, time, what ) -> appointments .... enddefine; Such a procedure would receive as input a pattern representing the day of the appointments to search, a pattern representing the time of such appointments and a pattern representing the descriptions of such appointments. A possible call could be: search_appointments( [March =], [== am], [==] ) This call would retrieve all the appointments in the diary which are in March AND in the morning. The structure of this procedure would be similar to that of appointments() (which could actually call search_appointments() with a special pattern to perform its task). -- -- Improvements --------------------------------------------------- If you have time try and write additional functions that allow more complex searches into the diary (for example all the appointments that are in March or July, or all the appointments that are after 11am). Another useful improvement would be to store the database on disk and retrieve it from disk so as to make the diary persistent (otherwise Pop-11 will forget all your appointments as soon as you quit ved). You could use the instructions database -> datafile('MY_FILENAME'); to save the database in a file called MY_FILENAME, and datafile('MY_FILENAME') -> database; to read a database from file (see HELP DATAFILE). Another improvement could be to represent also the duration of appointments (it could be a fourth list) and check that appointments do not clash when fixing them. -- Further reading ---------------------------------------------------- HELP * DATABASE Summarises Pop-11 database facilities Documentation on basic database facilities can be found in HELP * ADD * PRESENT, * LOOKUP, * REMOVE, * FLUSH, * MATCHES, * IT, * ISIN, *AREIN * WHICH * FOREACH * ALLPRESENT * FOREVERY. TEACH * POPCORE Is an online summary of a subset of Pop-11. TEACH * PRIMER Is a large introduction to most Pop-11 features. (Paper copies of this file are available for a small fee in the School library.) --- $poplocal/local/teach/diary --- The University of Birmingham 1996. --------------------------------