Prolog Introduction

by "Blag" - Senior Developer Evangelist

Return to Geeky Thursday

What is Prolog?


Prolog is a general-purpose logic programming language associated with artificial intelligence and computational linguistics.


Prolog is declarative. The program logic is expressed in terms of relations, represented as facts and rules.


Developed in Marseille, France.


If you have never used Logic Programming before...it's not that easy...


but it's really fun -;)

How to install Prolog?


There are plenty of free and commercial implementations of Prolog...

We're going to use SWI-Prolog as it looks like it's the most widely used...

It's available for Mac, Windows and Linux.

Who uses Prolog?


  • IBM -> For Natural Processing Language on Watson.
  • Genexus -> Cross-Platform, knowledge representation-based, development tool.
  • Microsoft -> For Windows NT.
  • Ericsson -> The first Erlang compiler was written in Prolog.

Starting out...


On a terminal, we simply need to use the command...

swipl


To load a source code file, we need to call it like this... [nameoffile].

Facts, Rules and Queries


A collection of facts and rules is called a knowledge base (or Database).

Prolog programs are knowledge bases, collections of facts and rules which describe some collection or relationships.

				
functional(haskell).

functional(erlang).

logical(mercury).

logical(prolog).
				

Believe it or not...this is a Prolog program...

How do we use it? We ask queries to it...we'll see how...

				
functional(prolog).

false.


functional(haskell).

true.



logical(X).

x = prolog ;

x = mercury.
				

Let's see a more complex example...

				
likes(blag,chocolate).

likes(aaron,chocolate).

likes(julia,vanilla).



eats(X,Y) :- likes(X,Y).
				

These are the queries that we can use...

				
likes(blag, chocolate).

true.


eats(julia,X).

x = vanilla.
				

Let's analyze this...

The first 3 lines are facts. They can either be true of false...

likes(blag,chocolate).

The last one is a rule...it will be true "if" who is eating a flavor...likes that flavor...otherwise, it will reply no...

eats(X,Y) :- likes(X,Y).

The left part is called the "Head" of the rule...and the right side is called the "Body".

As you can see, "Variables" are always written in Upper Case...

Unification


A pretty important concept in Prolog is unification...

And this basically means...two objects unify if they have the same value...

				
blag = blag.

true.


blag = julia.

false.


X = blag.

X = blag. true.


X = blag, X = julia.

false.
				

Recursion


Recursion is a key component in Prolog programming.

Recursion can be use in definitions, which makes it easier to understand.

				
likes(julia,vanilla).

icecream(vanilla,'banana split').



eats(X,Y) :- likes(X,Y), !.


eats(X,Y) :- icecream(Z,Y),

             likes(X,Z).
				

The ! means "stop".

				
eats(julia,'banana split').

true.


eats(julia,vanilla).

true.
				

Julia likes vanilla, so that's fine...but what about banana split?

banana split has vanilla on it...so if Julia likes vanilla, she must like banana split...

Simple but helps to explain recursion better, right?

Lists


Almost the only type in Prolog is the list...as I don't think variables count for that much -:P

List can and almost everytime are, divided into Head and Tail...being head the first element and tail the rest...

				
list([H|T]) :- write(H), nl,

               write(T).
               

               
list([erlang,haskell,prolog,falcon]).


erlang

[haskell,prolog,falcon]

true.
				

Recursion


We have already seen recursion on definitions...but recursion can be used in complex programs as well...

By calling the Head and Tail of a list, we can loop the list.

Arithmetics and Assignments


Prolog has its own notation...

8 is 6 + 2. true

Which is nice, because then we can do this...

X is 6 + 2. X = 8

And we can even use them in predicates...

double(X,Y) :- Y is X * 2.

double(2,X). X = 8.

3 < 5. true.

3 =< 5. true.

3 =:= 5. false.

3 =\= 5. true.

3 >= 5. false.

3 > 5. false.

Fibonacci List


Finally...we're going to make our first application...


So grab your favorite text editor and get ready...


Name your file "fibonacci.pl" (with lowecase).


And yes...you're right...Prolog uses the same extension as Perl...funny coincidence I guess...

				
fibo(NUM,A,B,[H|T]) :- (NUM > 1 -> 

                         H is A + B, 
                         
                         X is NUM - 1, 

                        (A =:= 0 -> 
                        
                          fibo(X,H,B,T); 
                          
                          fibo(X,H,A,T))).


fibo(_,_,_,[]).



fibonacci(NUM,R) :- fibo(NUM,0,1,X), 

                    !, 
                    
                    append([0,1], X, R).
				

When we run it we're going to see...


Making an LED Number App


This is one of my favorite codes of all time...


Name your file "ledNumbers.pl" (all in lowercase, only N in uppercase).

				
number(0,[[' _  '],['| | '],['|_| ']]).

number(1,[['  '],['| '],['| ']]).

number(2,[[' _  '],[' _| '],['|_  ']]).

number(3,[['_  '],['_| '],['_| ']]).

number(4,[['    '],['|_| '],['  | ']]).

number(5,[[' _  '],['|_  '],[' _| ']]).

number(6,[[' _  '],['|_  '],['|_| ']]).

number(7,[['_   '],[' |  '],[' |  ']]).

number(8,[[' _  '],['|_| '],['|_| ']]).

number(9,[[' _  '],['|_| '],[' _| ']]).
				
				
digits(0,[]).

digits(X,[H|T]) :- (X/10 > 0 -> 

                      H1 is floor(X/10), 

                      H is X mod 10, 
                    
                      digits(H1,T)), !.



accRev([],A,A).

accRev([H|T],A,R) :- accRev(T,[H|A],R). 



getDigits(L,R) :- digits(L,Y), accRev(Y, [], R).
				
				
show_records([]).

show_records([A|B]) :-

  print_records(A), nl,

  show_records(B).  



print_records([]).

print_records([A|B]) :-

  format('~w',A), 

  print_records(B).



merge([L], L).

merge([H1,H2|T], R) :- maplist(append, H1, H2, H),

                       merge([H|T], R), 
                       
                       !.
				
				
listnum([],[]).

listnum([H1|T1],[R|Y]) :- number(H1,R), 

                          listnum(T1,Y).



led(X) :- getDigits(X,Y), 

          listnum(Y,Z), 
          
          merge(Z,R), 
          
          show_records(R).
				

When we run it we're going to see...


Random Names


This App will generate 100,000 random names using two 16 elements arrays. (Ok...there are no arrays in Prolog).


We will measure the runtime.


Name your file "randomnames.pl" (all in lowercase).


				
name(0,'Anne'). name(1,'Gigi'). name(2,'Blag'). 

name(3,'Juergen'). name(4,'Marek'). name(5,'Ingo'). 

name(6,'Lars'). name(7,'Julia'). name(8,'Danielle'). 

name(9,'Rocky'). name(10,'Julien'). name(11,'Uwe').

name(12,'Myles'). name(13,'Mike'). name(14,'Steven'). 

name(15,'Fanny').



last_name(0,"Hardy"). last_name(1,"Read"). 

last_name(2,"Tejada"). last_name(3,"Schmerder"). 

last_name(4,"Kowalkiewicz"). last_name(5,"Swauerzapf"). 

last_name(6,"Karg"). last_name(7,"Satsuta").

last_name(8,"Keene"). last_name(9,"Ongkowidjojo"). 

last_name(10,"Vayssiere"). last_name(11,"Kylau"). 

last_name(12,"Fenlon"). last_name(13,"Flynn").

last_name(14,"Flynn"). last_name(15,"Tan").
				
				
full_names(100000, 100000,[]).

full_names(TOP,NUM,[H|T]) :- (NUM < TOP -> 

                              X is NUM + 1,

                              random_between(0,15,L),

                              random_between(0,15,R),

                              name(L,L1),

                              last_name(R,R1),

                              H = [L1,R1],

                              full_names(TOP,X,T),!).
				
				        
random_names(_) :- statistics(walltime, [_ | [_]]),

                   full_names(100000,0,_),

                   statistics(walltime, 
                   
                              [_ | [ExecutionTime]]),

                   write('Execution took '), 
                   
                   write(ExecutionTime), 
                   
                   write(' ms.'), 
                   
                   nl.                              
				

When we run it we're going to see...

1.741 seconds...not bad at all -:)

The same code run in different languages yields...

  • Ada --> 0.078 seconds
  • Julia --> 0.067 seconds
  • Python --> 0.185 seconds
  • Erlang --> 0.463 seconds

Decimal to Romans


This App will create a Roman Numeral based on a decimal number


This will include some nice commands...


Name your file "dectoromans.pl" (all in lowercase).


				
number(1000,'M'). number(900,'CM'). number(500,'D').

number(400,'CD'). number(100,'C'). number(90,'XC').

number(50,'L'). number(40,'XL'). number(10,'X').

number(9,'IX'). number(5,'V'). number(4,'IV').

number(1,'I').



numbers(0,[1000,900,500,400,100,90,50,40,10,9,5,4,1]).
				
				
toRomans(_,[],[]).

toRomans(NUM, [H|T]) :- (NUM >= H -> 

                           number(H,R), 
                         
                           write(R), 

                           X is NUM - H, 

                         (X > 0 ->
                         
                           numbers(0,T1),
                         
                           toRomans(X,T1),
                           
                           !;
                           
                           !);

                           toRomans(NUM,T)).
                           
                           
                           
romans(X) :- numbers(0,L), toRomans(X,L).
				

When we run it we're going to see...


Count Letters


In this example we're going to read a file and count how many time a letter appears...


Call your file "countletters.pl" (all in lowercase).


Create a file called "readme.txt" with the following text...


"'This is a text file that we are going to read it using Prolog.'"


				
main(X):- open('readme.txt',read,Str), 
          
          read(Str,Line), 
          
          X = Line,
          
          close(Str).



count_occur(List, Occ):- findall([X,L], 

                         (bagof(true,member(X,List),Xs), 
    
                         length(Xs,L)), Occ).



count_letters(Y) :- main(X), 

                    atom_chars(X,L), 
                    
                    count_occur(L,Y).
				

When we run it we're going to see...


That's it for now...


I hope you had some fun...


Logical Programming can really change the way you think...


And keep in mind...Prolog is highly used in Artificial Intelligence applications


Contact Information


Blag --> blag@blagarts.com

@Blag on Twitter

Go back home...