Quick Tutorial

This section is a tutorial introduction to the Amzi! Prolog development tools. It is not intended to be an introduction to Prolog. If you need an introduction to the Prolog language we recommend Adventure in Prolog.

The tutorial makes use of a simple adventure game, Duck World, to illustrate how to use the Amzi! tools to build complex applications. Accordingly, it is composed of a number of files.

(Why Duck World? Because Amzi! inc. is located in an old farm house backed up on conservation land. We bought ducks out of whimsy one day, which were later discovered by the fox in the woods. The ducks have proved to be an adventure.)

The tutorial demonstrates both the command-line (alis) and Windows-IDE interfaces to Amzi! Prolog.

This tutorial starts by testing some of the basic predicates of Duck World in the listener. It then goes through the full example, showing how the program is modularized, how it is compiled and run using the listener, and how it is linked into a distributable application.

The source code for Duck World can be found in the samples/prolog/ducks sub-directory.

Duck World

An adventure game is a simulation of an environment, real or imagined, that the user explores, usually with some goal in mind. Duck World is a simple adventure game, where the objective is to go from the house, through the yard, to the duck pen to get an egg, and back to the house again, without losing any ducks to the fox.

The commands for manipulating the environment are all entered as legal Prolog goals (ending in periods).

They are:

  • goto(X) - moves you to place X, where X can be either house, yard or pen.
  • take(X) - takes something if it's where you are; the egg is the only thing you're supposed to take.
  • chase(ducks) - how to get the ducks back in their pen.
  • quit - this, or any illegal command, will quit the game for you.
  • When you have brought the egg into the house the game ends.

    Starting the Listener

    Amzi! Prolog can be run using one of two different methods:

    To start the listener from the operating system command-line, type the input shown in the left box. To do this within the IDE, select the menu items shown in the right box. General instructions are given in italics.

    Command-Line alis Windows-IDE
    c>  alis
    Double-Click on Icon for the
    Amzi! Prolog IDE
    Listener / Start

    The copyright message will be displayed followed by the prompt, ?-

    Amzi! Prolog <version information>
    Amzi! Prolog Listener
    Copyright (c)1987-97 Amzi! inc. All Rights Reserved.
    Type  'quit.'  to exit
    ?-

    You are now in a Prolog listener, which is awaiting your command. Try out this classic, being careful to remember the single quotes and the ending period.

    ?- write('Hello World').
    Hello World

    Note: The listener does NOT have a full line editor at the ?- prompt, although it appears to behave that way in the IDE. You can type in characters and backspace to fix mistakes. You cannot use the mouse or cursor keys to edit a query. You can cut and paste from one line to the prompt, but you can only edit that line using the backspace key.

    (To exit, you would type "quit." or select Listener / End from the IDE menu.)

    Creating a Source File

    Before looking at the Duck World source code, create a small experimental file called DW.PRO.

    Command-Line alis Windows-IDE
    Use an editor to type in your code
    Save your file as dw.pro 
    File / New
    Type your code into the window
    File / Save As dw.pro 

    Type the following lines of Prolog code into DW.PRO:

    % Experiments
    nextto(house, yard).
    nextto(yard, pen).
    
    loc(you, house).
    
    move(Place) :-
      retract( loc(you, _) ),
      assert( loc(you, Place) ).

    Note, it is important to keep the clauses defining a predicate together, as the clauses of the predicate nextto/2 are. If the definitions are scattered, the program will seem to work properly when interpreted, but behave in an unexpected manner when compiled.

    Consulting a Source File

    To play with DW.PRO, consult it into the listener as shown:

    Command-Line alis Windows-IDE
    ?- consult(dw).
    yes
    Listener / Consult
    dw.pro

    You are now in the listener with DW.PRO consulted.

    Using the Listener

    Now that you've reached the listener, make sure your file was consulted by using listing.

    ?- listing.

    This will show you the predicates of dw.pro, although they will look a little different because the variables are renamed with an _ and a number, e.g. _0.

    You can try various queries from the listener.

    ?- loc(you, X).
    X = house

    You can test move.

    ?- move(yard), loc(you, X).
    X = yard
    ?- move(foobar), loc(you, X).
    X = foobar

    Because move doesn't check to see if the move makes sense, you might decide to add a goto predicate with more intelligence. You can enter it directly in the listener using add.

    ?- add.
    |  goto(P) :-
    loc(you, X),
    nextto(X, P),
    move(P).
    |  quit.
    ?-

    This is a useful technique for quick experiments, but the code typed in the listener is not entered into your source file. Because we want goto to be part of the game it is best to type it directly into the source file and then reconsult it.

    This can be done by moving from the listener to the editor. You can use the built-in IDE editor, or, under DOS, invoke the editor of your choice. In the IDE, simply selecting Listener/Reconsult will reconsult the last file (or project) consulted. The last file consulted is also remembered between sessions, so you begin a new IDE session by simply selecting Reconsult.

    (You need to reconsult, rather than consult, because consulting would will simply add a second copy of your program to the Prolog workspace. Listing would show two of every predicate.)

    Command-Line alis Windows-IDE
    Edit dw.pro in an editor
    then in the listener:
    ?- reconsult(dw).
    yes
    Edit dw.pro in its window
    File / Save
    Listener / Reconsult

    You can then test it.

    ?- goto(yard).
    yes
    ?- goto(pen).
    yes
    ?- goto(yard).
    no

    It didn't work right, which leads to the next section.

    Debugging

    goto lets you get into the pen, but doesn't let you get back out. First, you can use the listener to make sure the game is in the state required for testing. To do this enter the goals to place you in the pen.

    ?- retract(loc(you, _)), assert(loc(you, pen)).
    yes

    The listener gives you the ability to dynamically adjust the state of your application, effectively putting you in the middle of it. This, by itself, is a powerful tool for debugging.

    You can now trace the execution of goto(yard) to see why it is failing. To do this you need to start the debugger. Type:

    Command-Line alis Windows-IDE
    ?- debug.
    Listener / Debug On

    The debugger in alis is line-oriented, and is controlled from the keyboard. In the IDE, a separate debugger window is opened, which is controlled with the mouse. You enter your normal interaction with the program in the listener window.

    Next, type in the goal to be traced at the listener prompt, which is ??- for alis and ?- for the IDE:

    ?- goto(yard).

    To step through the Prolog code type:

    Command-Line alis Windows-IDE
    ? c
    Alternatively
    ? [Enter]
    Click on the "Creep" button

    Note the IDE does not display the ? prompt. (See the Debugger section for other options.)

    Calling: goto(yard)
    CALL:(1) goto(yard)    ? c
       Calling: loc(you,H64)
       CALL: loc(you,pen)    ? c
       EXIT: loc(you,pen)    ? c
       Calling: nextto(pen,yard)
       FAIL: nextto(pen,yard)    ? c
       FAIL: loc(you,pen)    ? c
       FAIL: loc(you,H64)    ? c
    FAIL: goto(yard)    ? c
    FAIL: goto(yard)    ? c
    no

    To leave the debugger

    Command-Line alis Windows-IDE
    ??- quit.
    Listener / Debug Off
    Or, Click on the "Stop"
    button

    The trace reveals that nextto(pen, yard) is different from nextto(yard, pen), so, to get goto/1 to work, a predicate that equates the two is needed. The solution chosen for Duck World is the predicate connect/2, which is used instead of nextto/2 in the goto/1 definition.

    connect(X, Y) :- nextto(X, Y).
    connect(X, Y) :- nextto(Y, X).

    This code can be added to the source file and the development process continues. This is the normal way to develop a Prolog application. Predicates are gradually added to the source file as the application grows. The application can be tested at any point during the development process and individual predicates can be tested and their execution traced to understand why the application is working the way it does.

    Modules

    As an application grows, it is natural to want to break it up into modules. At the simplest this means splitting the predicate definitions among various source files. These files can be consulted together and the application run from the listener.

    However, it is often preferred to keep some of the predicates hidden within a file and to allow only certain predicates to be called from other source files. This is done through two compiler directives (specified by :- in the source code), import and export. These directives specify which predicates will be visible outside of the source file (export), and which predicates the file is calling that it expects to find elsewhere (import).

    Included in the samples are two source files that illustrate this idea. They are:

    Even for compiled applications, there are usually at least a few predicates which remain in the dynamic database. It is often convenient to separate their definition to a separate file that also initializes them by asserting them into the dynamic database when the program starts up.

    In the case of Duck World, the loc/2 predicate is constantly being changed by the application and therefore is kept in the dynamic database. The file DUCKENV.PRO contains the code to initialize the database. Notice that it is consulted when main/0 is called.

    If you want to keep a dynamic predicate's definition in with compiled code, you can use the dynamic directive. It tells the compiler to keep the specified predicate in the dynamic database, rather than comiling it.

    For example, in this code loc/2 will be in the dynamic database while main and goto are compiled. dynamic is ignored for interpreted code.

    Running a Modular Application

    You can run the modularized Duck World from a listener by consulting it and calling main/0, the predicate that starts it running. (You can also call any of the other predicates of Duck World to see if they're working and trace them if they're not.)

    ?- consult([duck1, duck2]).                               
    ?- main.
    Welcome to Duck World
    Go get an egg
    >> goto(yard).
    You are in the yard
    >> .....

    Using alis and BAT Files

    main/0 is a special predicate for Amzi! Prolog because it is the main entry point into your program. When you include files to be consulted on the alis command line, alis first tries to call main/0 before establishing the listener environment. This means that alis can be used to launch your application without the need for compiled or linked code. Further, when alis finds a main/0 to call, it exits back to the operating system when it's finished, rather than staying in the listener.

    c>  alis duck1 duck2
    Welcome to Duck World
    Go get an egg
    >> quit.
    Quitter
    c>

    By creating a batch file, ducks.bat with the line "alis duck1 duck2", you can run Duck World by simply typing "ducks" at the operating system prompt.

    If you have a large number of files in your application, you can create a file like DUCKS.PRO that consults each of the files. Then only this one file need be specified on the alis command line.

    Using Projects

    You can create a project file (.ppj) by selecting Build / Project New from the IDE menu. Enter the name of your project, e.g. ducks.ppj. Next you will be presented with a dialog box which you can use to add files to your project. Double-click on duck1.pro and duck2.pro. Their names will appear in the window on the bottom. Click on "OK."

    Now instead of using Listener / Consult to individually consult each file, you can simply consult the project, which, in turn, consults each file in the project.

    Compiling

    Compiling Duck World is easily done:

    Command-Line alis Windows-IDE
    c>  acmp duck1
    c>  acmp duck2
    Build / Compile
    ducks.ppj

    Note, under the IDE we simply compile the project. This causes all the modified source files in the project to be recompiled.

    acmp can also be invoked with no arguments, in which case it will prompt you for the names of the files. See the Compiler section for more details.

    The result of compiling is a Prolog object file, in this case, duck1.plm and duck2.plm.

    Running

    The .plm files can be run from either alis or the IDE just as the .pro Files were. The only difference is they go faster and the debugger cannot trace them. If you wanted, you could run Duck World consulting the .pro file for one and loading the .plm file for the other. This way you could use trace on the predicates in the .pro file (duck2 in this example).

    ?- load(duck1), consult(duck2), main.

    This can also be accomplished in the IDE by setting up your project to include duck1.plm and DUCK2.PRO. When consulting projects (using Listener / Consult), .plm files are loaded and .pro files are consulted.

    With alis, the .plm files can be loaded from the command line, just as the .pro files were. This can be either directly

    c>  alis duck1.plm duck2.plm

    or by using an intermediate file to load the component files.

    c>  alis ducks

    Linking and Running

    To build a stand-alone application first create a Prolog load module (.xpl file) with the Amzi! Prolog linker, alnk.

    Command-Line alis Windows-IDE
    c>  alnk ducks duck1 duck2
    Build / Link
    ducks.ppj

    Note, under the IDE we just link the project to create an .xpl file with the same name as the project.

    Using alnk, the first argument is the name of the .xpl file. The next two files are the .plm files that are linked together.

    The .plm files (in this case duck1.plm and duck2.plm) are linked with alib.plm, the Prolog portion of the Amzi! engine, to form an application. (Hence, alib.plm must be somewhere in the PATH or AMZI_DIR.)

    Alnk can also be invoked with no arguments, in which case it will prompt you for inputs. See the Linker section for more details.

    To run Duck World, just type:

    Command-Line alis Windows-IDE
    c> arun ducks
    Build / Run
    ducks.xpl                    

    Distributing an Application

    If you decided to distribute Duck World, then to do so, you need these files for command-line environments:

    For Windowing environments, arun.exe would be replaced by your own C/C++, Visual Basic or other language program.

    Interfacing with Other Tools

    You can enhance the Prolog engine with your own built-in predicates written in C/C++, Delphi or Java.

    For example, you might want to use a graphical interface for Duck World with quacking ducks and the like. In this case the Logic Server API allows you to either extend the Prolog language with graphics predicates written in C/C++ that are called directly by the Prolog code, or to write the user interface to the code in C/C++ (or Visual Basic under Windows) and call embedded Prolog for the logic. You can combine the techniques, both extending and embedding Prolog in the same application.

    The section on the Logic Server API tells how integrate Prolog with other languages.

    Copyright ©1987-2000 Amzi! inc. All Rights Reserved.