Visual Prolog 7 TutorialsFundamental Visual PrologWritten by Sabu Francis In this tutorial, we will introduce a program that is developed on the Visual Prolog platform. The essential algorithms of the tutorial are the same as those that were developed in the Part 2 of the "Fundamental Prolog" Tutorial. Differences in Visual Prolog and Traditional PrologThe differences between traditional Prolog and Visual Prolog can be broadly divided into these categories:
Program Structure DifferencesDeclarations and DefinitionsIn Prolog, when we need to use a predicate we simply do so without any prior intimation to the Prolog engine about our intention. For example; in the earlier tutorial the grandFather predicate's clause was directly written down using the traditional Prolog's predicate head and body construction. We did not bother to inform the engine explicitly in the code that such a predicate construction is to be expected later. Similarly, when a compound domain is to be used in traditional Prolog, we can use it without first forewarning the Prolog engine about our intention to use the domain. We simply use a domain, the moment we feel the need for it. However, in Visual Prolog, before writing down the code for the clause body of a predicate, we would first need to declare the existence of such a predicate to the compiler. Similarly, before using any domains, they need to be declared and their presence is to be informed to the compiler. The reason such forewarnings are required in Visual Prolog is essentially to ensure that runtime exceptions are converted into compile time errors as far as possible. By "runtime exceptions", we mean the issues that turn up only at the time of running the program that were compiled with it. For example, if you had intended to use an integer as the argument of a functor, and instead of the integer you had erroneously used a real number, it would become a runtime error (in programs written using most other compilers, but not Visual Prolog) and the program would fail there. When you also declare the predicates and domains that are defined, such kind of positional grammar (which argument belongs to which domain), etc. is made available to the compiler. Therefore, when Visual Prolog performs a compilation, it checks the program quite thoroughly to weed out such grammatical and other mistakes. Because of this feature in Visual Prolog, the overall efficiency of a programmer improves. The programmer does not have to wait till the program is actually executed to detect a bug. In fact, those of you, who are experienced in programming, would understand what a life-saver this can be; for often, the particular sequence of events that is causing a runtime exception to happen at run-time may be so elusive that the bug may actually turn up after several years, or it may manifest itself in some crucially critical or other embarrassing situations! All this automatically implies that the compiler has to be given explicit instructions regarding the predicates and domains that exist in the code using appropriate declarations before the same are defined. KeywordsA Visual Prolog program consists of Prolog code which is punctuated into different sections by appropriate keywords that inform the compiler the code it has to generate. For example, there are keywords that differentiate the declarations from the definitions of predicates and domains. Usually, each section is preceded by a keyword. There is normally no keyword which signifies the ending of a particular section. The presence of another keyword indicates the ending of the previous section, and the starting of the next one. The exception to this rule, are the keywords "implement" and "end implement" The code contained between these two keywords indicates the code to be used for a particular class. Those of you who do not understand the concept of a "class" can, for now (i.e. in this tutorial), think of it as a module or a section of the overall program code. For the purpose of this tutorial, we'll introduce only the following keywords (given below). We are also giving the purpose behind these keywords, and the actual syntax can be easily learnt from the documentation. There are other keywords also in Visual Prolog, and those can easily be picked up in later tutorials and the documentation. The list of the keywords that you need to know in this tutorial is the following: implement and end implement Among all the keywords discussed here, this is the only one, which exists as a pair. Visual Prolog treats the code written between these two keywords as the code that belongs to one class. The name of the class MUST be given after the implement keyword. open This keyword is used to extend the scope visibility of the class. It is to be used just after the implement keyword. constants This keyword is used to mark a section of the code that defines some commonly used values in the program code. For example, if the string literal "PDC Prolog" is to be used in multiple locations throughout the code, then you can define a mnemonic (a short-form, easily remembered word) for the same thus: constants pdc="PDC Prolog". Note that the definition of a constant ends in a period (.). Unlike a Prolog variable, a constant should be a word starting with a lower case letter. domains This keyword is used to mark a section declaring the domains that would be used in the code. There are many variations for the syntax of such domain declarations, and they cater to the all the possible kinds of domains that would be used later on in the code. As this tutorial is a basic one, we shall not get into the finer details of the domain declarations that can be possible. To summarize here, you would be declaring the functor that would be used for the domain and the kind of domains that would form its arguments. Functors and compound domains were explained in detail in the previous part of the Tutorial. class facts This keyword designates a section, which declares the facts that would be used later on in the code of the program. Each fact is declared with the name used to signify the fact and the arguments that are used for the respective facts along with the domains that those arguments belong to. class predicates This section contains the declarations of the predicates that would be later defined in the clauses section of the code. Once again, the names that would be used for these predicates along with the arguments and the domains, to which the arguments belong to, would be indicated in this section. clauses Of all the sections that are present in a Visual Prolog code, this section is the one that closely mimics a traditional Prolog program. It contains the actual definitions of the previously declared predicates. And you would find that the predicates used here would follow the syntax as declared in the class predicates section. This section defines the main entry point into a Visual Prolog program. A more detailed explanation is given below. GoalIn traditional Prolog, whenever a predicate is defined in the code, the Prolog Engine can be instructed to start the code execution from that predicate onwards. However, that is not the case with Visual Prolog. Being a compiler it has the responsibility of producing efficiently executing code for the program you write. This code would not be actually executing at the same time the compiler is doing its work. Hence, the compiler needs to know beforehand the exact predicate from which the code execution would start, so that later on when the program is called to perform, it can do so from the correct starting point. As you may have guessed, the compiled program can run independently without the Visual Prolog compiler or the IDE itself. In order to do that, there is a special section indicated by the keyword Goal. Think of it as a special predicate that you would write without arguments. That predicate is the one from which the entire program execution will start. File ConsiderationsMany times, it may become cumbersome to put all the parts of the program into one file itself. It may even make the program unreadable and sometimes incorrect. Visual Prolog has the capability of dividing the program code into separate files using the IDE (Integrated Development Environment) and it is possible to write neat pieces of code into separate files using that IDE. When it is done in that manner, things that are to be used commonly can be accessed across files. E.g. If you have a domain that is to be used in multiple files, then the declaration of that domain is done in a separate file, and that file is then accessed from other files. However, for the purpose of simplifying this particular tutorial, we shall predominantly be using only one file to develop the program code. In the course of constructing the program, the IDE would automatically create some more files which we can ignore for the time being. We can learn about them in future tutorials. Scope Access IssuesVisual Prolog divides the total program code into separate parts, each part defining one class. In object oriented languages, a class is a package of code and its associated data which is put together. This requires more explanation which would be available in later tutorials. As noted earlier, for those of you who are not familiar with object oriented programs, you can think of a class loosely as being synonymous to modules. Normally, Visual Prolog defines each class in its own separate file. During the program execution, it often so happens that the program may need to invoke a predicate that is actually defined in another class (file). Similarly, data (constants) or domains defined in a class may need to be accessed from a different file. Visual Prolog allows such cross class code/data references using a concept called scope access. This can be understood by an example. Suppose there is a predicate called pred1 defined in a class called class1 (which is written down in another file using the IDE), and we need to call that predicate in the clause body of some other predicate, pred2 in a different file (say class2) then this is how pred1 would be called within the clause body of pred2 : pred3:-
...
!.
pred2:-
class1::pred1, %pred1 is not known in this file.
In the above example, you can see that the clause body of pred2
calls two predicates pred1 and pred3.
As pred1 is defined in another file (which defines class1),
the word class1 with the token :: (two colons) precedes the word
pred1. This can be called as a
class qualifier.
But the predicate pred3 is defined within the same file as pred2 itself. Hence there is no need to indicate class2:: prior to the predicate call for pred3. This behavior is technically explained thus: The scope visibility of pred3 is within the same scope of pred2. Hence there is no need to clarify that pred3 is from the same class as pred2. The compiler would automatically look for the definition of pred3 within the same scope area as defined for class2. The scope area of a particular class definition is restricted to the class that is implemented in a particular file (i.e. code that is written within the implement - end implement keywords). The predicates defined therein can call each other without the class qualifier and the double colon (::) token preceding it. The scope area of a class can be extended by using the open keyword. This keyword informs the compiler to bring in names (of predicates / constants / domains) that were defined in other files. If a scope area is extended, then we need not write the class qualifier with the double colon. open class1
...
pred3:-
...
!.
pred2:-
pred1, %Note: "class1::" qualifier is not needed
%anymore, as the scope area
%is extended using the 'open' keyword
pred3,
...
Object OrientationThe current version of Visual Prolog is a strongly object oriented language. The ENTIRE code which is developed for a program is put into appropriate classes, as needed. This happens by default, even if you are not interested in the object oriented features of the language. You would notice this feature in the example given in this tutorial also. The code is inserted into a class called "family1" even though we would eventually not use any objects created from that class. Instead, we would use publicly accessible predicates of the code within that class directly. This tutorial will not handle the object oriented features of the language. Future tutorials would extend this concept, and even actually use the object oriented features. A Full Fledged Example: family1.prj6
Download: Source
files of the example project used in this tutorial. Let us now put all the knowledge we've gathered together to create our first Visual Prolog program. This will contain the same basic logic that was explored in the Tutorial "Fundamental Prolog. Part 2". All the code that is to be written for this tutorial is shown below. It has to be written into the file called family1.pro. The actual code writing will be done using the Visual Prolog IDE (Integrated Development Environment). There are some more files that are needed for the tutorial, but those would automatically be generated and maintained by the IDE. The step by step instructions (using screenshots) for utilizing the IDE to develop the program will shortly follow. But first of all, let us acquaint ourselves with the main code of the program: implement family1 open core constants className = "family1". classVersion = "$JustDate: $$Revision: $". clauses classInfo(className, classVersion). domains gender = female(); male(). class facts - familyDB person : (string Name, gender Gender). parent : (string Person, string Parent). class predicates father : (string Person, string Father) nondeterm anyflow. clauses father(Person, Father) :- parent(Person, Father), person(Father, male()). class predicates grandFather : (string Person, string GrandFather) nondeterm anyflow. clauses grandFather(Person, GrandFather) :- parent(Person, Parent), father(Parent, GrandFather). class predicates ancestor : (string Person, string Ancestor) nondeterm anyflow. clauses ancestor(Person, Ancestor) :- parent(Person, Ancestor). ancestor(Person, Ancestor) :- parent(Person, P1), ancestor(P1, Ancestor). class predicates reconsult : (string FileName). clauses reconsult(FileName) :- retractFactDB( familyDB), file::consult(FileName, familyDB). clauses run():- console::init(), stdIO::write("Load data\n"), reconsult("fa.txt"), stdIO::write("\nfather test\n"), father(X, Y), stdIO::writef("% is the father of %\n", Y, X), fail. run():- stdIO::write("\ngrandFather test\n"), grandFather(X, Y), stdIO::writef("% is the grandfather of %\n", Y, X), fail. run():- stdIO::write("\nancestor of Pam test\n"), X = "Pam", ancestor(X, Y), stdIO::writef("% is the ancestor of %\n", Y, X), fail. run():- stdIO::write("End of test\n"). end implement family1 goal mainExe::run(family1::run). Step 1: Create a New Console Project in the IDEStep 1a. After starting the Visual Prolog IDE, click on the menu item from the menu.
Step 1b. A dialog would be presented to you. Enter all the relevant information. Ensure that the UI Strategy is Console and NOT GUI.
Step 2: Build an Empty ProjectStep 2a. When the project is just created, the IDE would display the following project window. At this point in time, it does not have any clue about what files the project is dependent on. It does, however create the basic source code files for the project. Step 2b. Use the menu item of the menu, to compile and link the empty project to create an executable file which basically does not do anything. (At this point it time, it would not generate any errors either) While building the project, take a look at the messages that are dynamically
displayed in the Messages window of the IDE. (In the case the
Messages window is not visible, you can turn it on using the
menu of the IDE) You will notice that the IDE intelligently pulls in ALL
the necessary PFC (Prolog Foundation Classes) modules into your project.
PFC classes are those classes which contains the basic functionality on
which your programs would be built. Step 3: Populate the family1.pro with the Actual CodeStep 3a. The default code inserted by the IDE is very basic and does not do anything useful. You would need to delete the entire code and copy and paste the actual code of family1.pro (given in this tutorial) into that window. |
|
|