Software Secret Weapons™  
Prolog posted by Pavel Simakov on 2005-11-16 14:02:39 under Lambda
view comments
 


Prolog.
The name stands for PROgramming in LOGic. Prolog is a programming language that uses a small set of basic mechanisms to create surprisingly powerful programs. These mechanisms are pattern matching, tree based data structuring and backtracking.

Prolog Clauses and Predicates
The sentence-like constructs of the Prolog language are called assertions or clauses. Prolog clauses are usually described as being of the following two varieties: Facts or Rules, although a fact can be regarded as being just a degenerate rule. Collections of related facts and rules are said to comprise Predicates, which may be regarded as something like the compound sentences of a natural language because they consist of a collection of conjoined simple clauses.

Database
A Prolog Program, which is also called a database or module, is a collection of predicates.

Fact
Facts are the sentence-like constructs of the Prolog language that have the following form:


	name(arg1, arg2, ..., argn).

Below we can see several instances of three Gender, Farther, Mother facts being created.


        /* family.pl - a simple database for a family */

	%This is a fact which states that “al” is a “male” and “anne” is a “female”
	gender(al,male).
	gender(arthur,male).
	gender(anne,female).
	gender(buck,male).
	gender(barbara,female).
	gender(betty,female).

	%This is a fact which states that “arthur” has “buck” as a farther
	father(arthur,buck).
	father(al,buck).


	%This is a fact which states that “al” has “Barbara” as a mother
	mother(al,barbara).
	mother(anne,betty).

Rules
Rules are the sentence-like constructs of Prolog that have the following form:


	[head] :- [body].

where head denotes a structure called the head of the rule, the symbol :- is called the neck (should be read as "if"), and body denotes a sequence of structures called goals that comprise the body of the rule. As is the case with all Prolog clauses, rules must end with a period.

They combine existing facts or are derived from existing facts. Rules use variables so they can be applied to any instance of the fact. Variables used in queries are the same once used in the rules, but their purpose is different. In queries they are resolved to specific facts. In rules they are used to define related sets of facts.


	parent(X,Y) :- father(X,Y).
	parent(X,Y) :- mother(X,Y).

Arity
Number of arguments in the prolog fact or rule.


	achieve/2 

In this notation Arity is “2” and indicates that archive takes two variables. Two predicates that have same name but different Arity are considered to be different predicates. The following two clauses belong to two different predicates (good/2 and good/3) because although they have the same name, they have a different number of arguments.


	good(peanut_butter, jam). 
	good(peanut_butter, cheese, banana). 

Query
These allow one to query fact database. A query might or might not have variables. Queries


	?- mother(al,betty).
	no
	?- mother(al,barbara).
	yes
	?-

have no variables. In this case Prolog evaluates them to yes or no. Query with two variables X and Y is presented below.


	?- father(X,Y).
	X=arthur,
	Y=buck;

	X=al,
	Y=buck;

	X=amber,
	Y=buck;

	X=anne,
	Y=boris;

	X=barbara,
	Y=charles;

	X=betty,
	Y=cuthbert;

	X=boris,
	Y=charles;

	X=buck,
	Y=calvin

	no
	?-

It returns a list of matching facts from fact database. For each match in the list we have a pair of values for X and Y that exists in facts database for facts that satisfy the query. The “no” at the end indicates that no more matches can be found. The scope of variables is one clause; there is no such thing as a global variable.

Variables
These start with an upper case letter and used in queries and rules.

Backtracking
Backtracking is an algorithm for answering the query. When Prolog tries to answer a query, it goes through a matching process. It tries to match the predicates on the right-hand side of the rule from left to right, binding variables when it finds a match. If a match fails, it may be because of the bondings in matches to the left. In that case, the interpreter backtracks - it returns to the nearest previous binding and tries to find a different match. If that fails, it backtracks some more.

Unification
Unification is the principal operation that the Prolog interpreter undertakes to prove claims and respond to queries. Unification is essentially a pairwise matching process. This process is straightforward in the case of simple or elementary terms such as atoms, numbers, and strings. For example, two atoms match, and are said to unify, if and only if they are the same atom. Similarly, pairs of numbers or strings unify just in case they are the same. Pairs consisting of lists or structures also unify just in case they are the same; but, the unification process becomes somewhat more complicated with these more complex terms. Complex terms such as structures are actually composed of elementary terms, and the process unifying structures is based upon the unification of these elementary constituents. For example, a structure is composed of a name, which is an atom, together with a sequence of arguments, which may be any terms. Hence, the unification of a pair of structures is performed on the basis of their names, the number of their arguments, and the arguments themselves; that is, two structures can be said to unify if their names match, they have the same number of arguments, and their arguments unify.

Consulting
One can load a set of predicates into the Prolog workspace. This is called consulting. After consulting the predicates are available for query. Instead of consulting, one can load compiled version of predicates.


	?- consult(‘c:\family.pl’).
	% using compile/1 is MUCH faster
	consulting(family.pl)
	consulted(family.pl,time(50))
	yes
	?-

Tracing
We can use built in predicate to trace execution of queries. Tracing can be done with predicate trace.


	?- trace(grandfather(al,Daddio)).
	Call: grandfather(al,_2409) : -
	 !!! dynamic(grandfather/2)
	 Call: parent(al,_2959) : -
	  !!! dynamic(parent/2)
	  Call: father(al,_2959) : -
	   !!! dynamic(father/2)
	  Exit: father(al,buck)
	 Exit: parent(al,buck)
	 Call: father(buck,_2409) : -
	  !!! dynamic(father/2)
	 Exit: father(buck,calvin)
	Exit: grandfather(al,calvin)
	Daddio=calvin;

	Redo: grandfather(al,calvin)
	 Redo: father(buck,calvin)
	 Fail: father(buck,_2409)
	 Redo: parent(al,buck)
	  Redo: father(al,buck)
	  Fail: father(al,_2959)
	  Call: mother(al,_2959) :-
	   !!! dynamic(mother/2)
	  Exit: mother(al,barbara)
	 Exit: parent(al,barbara)
	 Call: father(barbara,_2409) : -
	  !!! dynamic(father/2)
	 Exit: father(barbara,charles)
	Exit: grandfather(al,charles)
	Daddio=charles;

	Redo: grandfather(al,charles)
	 Redo: father(barbara,charles)
	 Fail: father(barbara,_2409)
	 Redo: parent(al,barbara)
	  Redo: mother(al,barbara)
	  Fail: mother(al,_2959)
	 Fail: parent(al,_2959)
	Fail: grandfather(al,_2409)
	no
	?-

Object Oriented Prolog
I personally feel deprived of Objects when I had to do a project with Prolog. So it happens that Prolog support object-oriented concepts. There are some large scale efforts to provide support for OOP in prolog. For example: Logtalk - http://www.ci.uc.pt/logtalk/logtalk.html The Logtalk is about +9000 lines of code and is not easy to pick and run with unless you are an expert in Prolog.

There is light weight approach that seems good enough for many of mere mortals at http://www.prologonlinereference.org/archives/oop.zip. This Prolog Object Oriented Programming implementation under SWI Prolog supports:

  • abstract module definitions;
  • modules inheritance;
  • predicates encapsulation;
  • predicates redefinition (through Prolog polymorphism);
  • event oriented programming.

The current Prolog OOP implementation has been programmed according to:

  • allow users to understand exactly what is happening, and how;
  • avoid to add a great number of new predicates to the Prolog system;
  • remain into the framework of Prolog programming, without inventing a new language;
  • keep things as simple as possible, although powerful.
An example of defining classes Person and Book is below:


	% person.pl
	:- module(person, []).
	
	:- private(name/1).
	:- public(age/1).
	:- public(get_name/1).
	:- public(set_name/1).

	name(Name) :-
		atom(Name).

	age(Age) :-
		integer(Age).

	get_name(Name) :-
		this(This),
		This:name(Name).

	set_name(Name) :-
		this(This),
		This<-name(Name).


	% book.pl
	:- module(book, []).

	:- extend_module(gift).

	:- private(price/1).
	:- public(set_price/1).
	:- public(title/1).
	:- public(author/1).

	price(Price) :-
		number(Price).

	set_price(Price) :-
		<-price(Price).	% Direct reference to 'this'

	title(Title) :-
		atom(Title).

	author(Author) :-
		atom(Author),
		instance_of(Author, person).


Prolog in Java
Several Prolog implementations exist that directly support Java.

Sources
I have assembled this document for my personal reference using some of the resources below.

Comment (1)

  • Comment by Heysem — October 20, 2007 @ 4:59 pm

    happy_with(me,this_work).

    A nice compilation to begin with. Thanks,


Leave a comment


  Copyright © 2004-2007 by Pavel Simakov SourceForge.net Logo