This section is an introduction to 'webbling' and describes all the elements of a WebLS logic-base and how to specify them.
A logic-base in WebLS consists of:
Facts are gathered from the user, or distilled from other facts. Examples of facts are: the error message, the programming language, the organization type and the operating environemnt. Rules are of the form if-then and check the values of facts to determine the answer(s). Questions define how to gather information from the user via HTML forms. Answers, notes, headers and footers define how to display the dynamically generated HTML document for the user.
The following syntax is used in the examples below:
You must keep all the like items together in your logic-base. That is all the if-then rules must be contiguous, as must all the question, answer and note declarations. So your logic-base looks generally like this:
% Operator definitions :-op( . . . % System variables :-asserta(system( . . . % Questions question( . . . question( . . . % Rules if . . . then . . . if . . . then . . . % Answers answer( . . . answer( . . . % Notes note( . . . note( . . .
Facts are stored in the logic-base as name-value pairs. For example: the 'environment' fact has the value 'Windows 95', the 'programName' fact has the value 'Amzi! IDE'. Facts can also have multiple values (a list). This is useful for collecting a list of interests, for example.
Some facts WebLS does not ask the user for values for. Instead they are distilled from rules. Usually this is done to group a set of related facts together. An example of a distilled fact is 'language', which has the value 'C/C++' if the fact 'languageTool' has any one of these values: 'Visual C++', 'Borland C++', or 'Watcom C++'.
For each fact whose value is entered by the user, you need to define how the question is displayed on an HTML form. WebLS implements three basic methods using HTML form components. They are:
Below is an example of each. This is how we ask for the 'errorCode' fact. The 5 is the HTML form field length and $none$ is the default value.
question(errorCode, [ prompt = $What error code was displayed or 'none'?$, ask = field, length = 5, default = $none$ ]).
This is how we ask for a value from a list. The square brackets are used to bracket the list of choices.
question(environmentNameVer, [ prompt = $What environment are you using?$, ask = menu(['Windows 3.x', 'Windows 95', 'Windows NT', 'DOS', 'Linux']), style = radio ]).
Lists can also specify a style. There are 4 choices:
listbox |
a pull-down list used to select a single item |
radio |
a list using radio buttons to select a single item |
listboxMultiple |
a pull-down list that allows multiple items to be selected |
checkbox |
a list using checkboxes that allows multiple items to be selected |
The following is an example of checkbox, which allows the user to select multiple values from the list using the [ctrl] key and the mouse. You use the 'include' comparator to check multivalued facts (see If-Then Rules below).
question(environmentNameVer, [ prompt = $What environments are you using?$, ask = menu(['Windows 3.x', 'Windows 95', 'Windows NT', 'DOS', 'Linux']), style = checkbox ]).
This is how we ask a yes/no question:
question(usingDCG, [ prompt = $Are you using DCG in your Prolog module?$, ask = yes_no ]).
When naming your questions, we recommend you start with a lowercase letter and not use any special characters. This allows you to use the fact names in your rules without surrounding them with single quotes. Also to avoid naming conflicts we recommend you NOT use field names of the form [name][number] (otherwise multivalued fields will not work properly).
If question names begin with an uppercase letter, have spaces in them or contain any characters other than letters, numbers and underscores, then they must be enclosed in single quotes ' '.
In order to reduce the number of interactions with the user, WebLS supports the concept of related facts. Entirely optional, they allow you to specify what facts are related to each other. It lets you 'group' facts together, so all the facts for a particular hypothesis can be gathered in a single form.
Here is how related facts are added to the question definitions:
question(environmentNameVer, [ prompt = $What environment are you using?$, ask = menu(['Windows 3.x', 'Windows 95', 'Windows NT', 'DOS', 'Linux']), related = [memSize, processorType] ]).
This says that 'memSize' and 'processorType' are related to 'environmentNameVer'. When the rules are executed, if WebLS is going to ask the user for environmentNameVer, it will also ask for the other two facts as well.
The heart of the logic-base is the rules. Rules can either directly determine the problem, or they can determine other facts (distilled facts). Here is a simple rule:
if errorMessage = 'Code too long to load' then problem = srcbufTooSmall.
It says if the fact 'errorMessage' has the value specified then the problem is 'srcbufTooSmall'. Now there is nothing particularly difficult or remarkable about this rule, nor is there about most of the rules in WebLS. What is notable is that the rules are easy to read and can appear in the logic-base in any order. The WebLS 'inference engine' (that's a fancy way to say search and pattern matching engine) scans the rules looking for ones that 'succeed.' A rule is said to succeed when all of the facts on the 'if' side match correctly.
Before we examine the inference engine, lets look at some more rules and how answers are outputted.
if languageTool = 'Visual C++' or languageTool = 'Borland C++' or languageTool = 'Watcom C++' then language = 'C/C++'.
This rule distills the fact 'language' from the user-provided fact 'languageTool'. This allows us to simplify rules such as the following:
if language = 'C/C++' and apiFunction = 'lsInit' and ((errorMessage = 'GPF (General Protection Fault)' and environmentNameVer = 'Windows 3.x') or environmentNameVer = 'DOS') then problem = cLargeModelRequired.
Note here that more of the power of the rule language becomes evident. We can use 'and', 'or' and parenthesis to check facts. Also, not shown here, is the ability to check if an fact is 'not equal' to a particular value. You can use these comparators: =, \= (not equal), >, <, >= and <=. This sorts by the ASCII character codes so 'A' < 'B', 'c' > 'D', '2' < 'E'.
For checking multivalued facts use 'include' as follows:
if whys include 'Intelligent components for Internet' or what = 'Website construction' or what = 'Other' then tool = webLS.
For each fact in the rule-base we had to define its attributes. Similarily for every problem, we have to define the nature of the answer and how it is outputted. WebLS offers three methods:
Lets look at some examples. First outputting HTML text:
answer(cLargeModelRequired, [ text = [$16-bit C/C++ applications require the large memory model. $, $Failure to use it leads to immediate GPFs.$] ]).
When the problem is 'cLargeModelRequired', the specified text is outputted. Optional headers and footers may surround the answer text (see below).
If you would rather keep the answers in separate HTML documents, you can send them out as shown in this example:
answer(lsxNotLoaded, [ htmlFile = 'lsxintro.htm' ]).
Another feature of answers is that you can also define a list of notes to accompany the answer. Notes are outputted after the answer separated by a horizontal rule. Notes are defined like text answers as follows:
note(debugEmbed, [ text = [$For more information on debugging embedded Prolog modules $, $we suggest you see $, $<A HREF="ftp://ftp.amzi.com/pub/articles/APIDEBUG.TXT">Debugging Hints</A>.$] ]).
Notes are used by adding a notes list to the answer. Remember lists are enclosed by square brackets. For example:
answer(cLargeModelRequired, [ text = [$16-bit C/C++ applications require the large memory model. $, $Failure to use it leads to immediate GPFs.$], note = [debugEmbed, cLibraries] ]).
Your logic-base is kept in a file called amzicgi.lb'.
Before you start writing rules, there is some required header information. It reads as shown below. The first seven lines define new operators in WebLS and should not be changed or deleted and they must remain at the start of the file.
:- op(790, fx, if). % prefix operator :- op(780, xfx, then). % infix operator :- op(775, xfy, or). % infix that can be linked :- op(770, xfy, and). % infix that can be linked :- op(700, xfx, <=). % infix operator :- op(700, xfx, include). % infix operator :- op(700, xfx, exclude). % infix operator
Next follows a couple of definitions to enable debugging. Note double backslashes are needed under Windows because backslash \ is the 'escape' character in strings (exactly like 'C') so \n means a newline character.
:- asserta(system('Log File', 'C:\\WebLS\\logs\\trace.htm')). :- asserta(system('Log File URL', 'file:///C:/WebLS/logs/trace.htm')). :- asserta(system('Results File', 'C:\\WebLS\\logs\\results.dat')).
Under BSD the file and directory names might look like this:
:- asserta(system('Log File', '/usr/amzi/web/trace.htm')). :- asserta(system('Log File URL', 'http://www.amzi.com/trace.htm')). :- asserta(system('Results File', '/usr/amzi/logs/results.dat')).
Note, the setting for 'Results File' is only used in the Professional Edition.
The next lines define a number of system variables that are used by the inference engine. These let you set the title, headers and footers:
:- asserta(system('Body Args', $bgcolor=#FFFFFF text=#000000$)). :- asserta(system('Title', $Amzi! Internet Site Guide$)). :- asserta(system('Header', $<H2><IMG SRC="/starry.gif" HSPACE=10> Amzi! Internet Site Guide</H2>$)). :- asserta(system('Footer', $<FONT SIZE=-1>Copyright ©1996 Amzi! inc. All Rights Reserved.$)). :- asserta(system('Form Action', 'Executable Path')). :- asserta(system('Goal', ['resource', 'tool'])).
The system variables are as follows:
There are some optional items you might want to define in your logic-base. There are these special answers:
There are these special notes:
Examples of each of these follows below. Make sure you put these with the other answers or notes in your logic-base.
You can also define headers and footers for each of your goals. For example, if one of your goals is 'tool':
answer(toolHeader, [ text = [$<HR><P><FONT SIZE=3><I><B>We recommend these tools, products and $, $services for you...</B></I></FONT><P><UL>$] ]). answer(toolFooter, [ text = [$<LI>All <A HREF="/catinfo.htm">Amzi!</A> products have a 60-day $, $moneyback guarantee, include free tech support (via internet, $, $phone and fax), are not copy protected and are royalty-free.</UL>$] ]). answer(noAnswer, [ text = [$We are unable to diagnose your problem at this time. $, $Please e-mail a description of your problem to $, $<A HREF="mailto:support@amzi.com">support@amzi.com</A>. $, $You should receive a reply in 48 hours or less.$] ]). note(systemError, [ text = [$<HR>Please write down the above message and what you were $, $doing when this problem occurred, including the values you $, $typed into the forms. E-mail this information $, $to <A HREF="mailto:info@amzi.com">us</A>. Thank you.$] ]). note(firstFormHeader, [ text = [$Welcome to the Amzi! Internet Site, let me be your guide...<P>$] ]). note(firstFormFooter, [ text = [$<A HREF="mailto:webmaster@amzi.com">webmaster@amzi.com</A>$] ]). note(answerHeader, []). % this means there is no header note(answerFooter, [ text = [$<P><HR><P>This is an experimental version of our new automated $, $technical support system. We are very interested in hearing $, $your feedback at <A HREF="mailto:info@amzi.com">info@amzi.com</A>. $, $We would be especially grateful if this system does not provide you $, $an answer, if you can tell us what your form inputs were and $, $describe your problem. $, $We'll e-mail you an answer and try to add it to this system.$, $<P>Thank you! $] ]).
Copyright ©1996 Amzi! inc. All Rights Reserved.