Wakatta!

Like Eureka!, only cooler

Seven Languages in Seven Weeks Prolog Day 1

The third language in the series is Prolog. I first encountered it at university many years ago, and found it a really exciting and different language.

The exercises we had to do at the time were significantly more complex (computing symbolic derivatives and integrals) that what the book proposes, so I have to say I didn’t really learn anything.

About Prolog

Prolog is really different. A lot of languages claim to be, but with unification and backtracking as the core control mechanisms, Prolog certainly stands apart.

Basically, Prolog could be seen as a kind of database engine: it is possible to define relations that represent set of facts, as in the Relational model. But the notion of rules takes Prolog beyond that: each rules defines how to create new facts from known ones (either defined, or previously created from rules too); and each query is an attempt to find a fact that matches the query terms.

Given the definition above, it might seem surprising that Prolog could be good for anything but logic. Yet this is a Turing Complete language, and there are many other areas where a Prolog solution can feel quite natural.

Still, logic is the main strength of Prolog (which comes from the French Programmation Logique), and a number of limitations of the implementations restricts it to that niche.

A note on building GNU Prolog 1.4.0 on MacOS X 10.7 (Lion)

The book recommends using GNU Prolog (for reasons that will become clear on Day 3), but I have been using SWI Prolog since I first needed a reliable Prolog engine at university, so I started the exercises with the latter.

Eventually, I tried to port my code to GNU Prolog, and found that it would crash. In practice, this is what the error looks like:

1
2
3
4
5
6
GNU Prolog 1.4.0
By Daniel Diaz
Copyright (C) 1999-2011 Daniel Diaz
| ?- I1 is 1 + 1.

Fatal Error: Segmentation Violation

In other words, a basic arithmetic operation causes a segmentation fault.

Fortunately, the users-prolog mailing list had the answer: Lion uses llvm-gcc by default, which causes problems for a number of software packages.

I use Homebrew to install new packages; the formula for GNU Prolog contains a declaration that requires the build to use gcc instead of llvm-gcc. But because gcc is actually llvm-gcc, somehow this declaration is not working. So, digging a bit deeper, I found another post with the solution: an explicit --use-gcc flag.

So with the following:

1
sudo brew install gnu-prolog --use-gcc

GNU Prolog compiles into something useable.

Exercises

The exercises today are very basic,

A knowledge base about books

Rather than a collection of my favourite books (which would take too long), I just input a few from the Pragmatic Bookshelf:

Book Knowledge Base (books.pl) download
1
2
3
4
5
6
7
8
9
10
11
% book(A, B) means A wrote book B

book(bruce_tate, seven_languages_in_seven_weeks).
book(dave_thomas, programming_ruby).
book(chad_fowler, programming_ruby).
book(andy_hunt, programming_ruby).
book(chad_fowler, rails_recipes).
book(chad_fowler, the_passionate_programmer).
book(andy_hunt, pragmatic_thinking_and_learning).
book(andy_hunt, pragmatic_unit_testing).
book(andy_hunt, practices_of_an_agile_developer).

Querying it:

Querying the book knowledge base
1
2
3
4
5
6
7
8
9
10
11
| ?- book(andy_hunt, B).

B = programming_ruby ? a

B = pragmatic_thinking_and_learning

B = pragmatic_unit_testing

B = practices_of_an_agile_developer

yes

The a after the first answer is the command to display all the solutions.

Music Knowledge Base

Music Knowledge Base (music.pl) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
% plays(A, B) means A plays B

plays(jimmy_hendrix, guitar).
plays(eric_clapton, guitar).
plays(jimmy_page, guitar).
plays(neil_young, guitar).

plays(diana_krall, piano).
plays(harry_connick_jr, piano).
plays(ray_charles, piano).
plays(jerry_lee_lewis, piano).

% style(A, B) means A plays B style music

style(jimmy_hendrix, rock).
style(jimmy_page, rock).
style(neil_young, rock).
style(jerry_lee_lewis, rock).

style(diana_krall, jazz).
style(harry_connick_jr, jazz).

style(rays_charles, blues).
style(eric_clapton, blues).

Then finding all the known guitar players is just:

Guitar Players
1
2
3
4
5
6
7
8
9
10
11
| ?- plays(A, guitar).

A = jimmy_hendrix ? a

A = eric_clapton

A = jimmy_page

A = neil_young

no

Not an exercise, but just to highlight the similarity with the relational model, here is a kind of join:

Rock Piano Players
1
2
3
4
5
| ?- style(A, rock), plays(A, piano).

A = jerry_lee_lewis ? a

no

And this wraps up Day 1.

Comments