Pack your queries as Prolog predicates
One of the nice things about Prolog is that it can be used to name primitive queries. The named queries (predicates) can be combined with each other and other Prolog primitives to build more complex rules about the domain. Learning that is the goal of this lesson. The important take-home message is make your predicates small. We start with some examples.
Starting a program file
?- emacs. in the toplevel to start the built-in editor. Use
File/new... to create a new file, say
demo.pl. Below is a
skeleton for the file. This skeleton defines a Prolog module
and imports the core RDF library and RDF-Schema libraries, which
suffices for our purposes.
:- module(demo, [ ]). :- use_module(library(semweb/rdf_db)). :- use_module(library(semweb/rdfs)).
Adding the first rule
A good rule to start with is
event(X), which states that X is an event.
Adding this rule to the template above results in this file below. Note
that we exported event/1 from the module to make it available, we
added the rule and a comment. Of course, the comment is optional, but it
is used by ClioPatria to create an online manual for you.
:- module(demo, [ event/1 % ?Event ]). :- use_module(library(semweb/rdf_db)). :- use_module(library(semweb/rdfs)). %% event(?Event) % % True if Event is an event in the Simple Event Model. event(Event) :- rdfs_individual_of(Event, sem:'Event').
After saving the file, the file can be compiled from the toplevel or through the menu entry Compile/Compile buffer. Next, we can query the database. Use SPACE to get the next answer and RETURN to stop.
?- event(X). X = poseidon:event_2005_001 ; X = poseidon:event_2005_002 ; ...
Note that this rule represents a clean logical statement. With an unbound X, it enumerates all events while given a bounded X, it acts as a boolean test whether the given X is an event.
A more complicated example
In this example we wish to relate an event to a location on the globe.
One of the complications here is that RDF literals always represent
text (a string value), while latitude and longitude are normally
expressed as floating point numbers. Please add the code below to
demo.pl and add event_point/2 to the export-list.
%% event_point(?Event, ?Point) % % True if Event happened at point(Lat,Lon), where Lat and Lon % are the latitute and longitude of the event in decial degrees. event_point(Event, point(Lat, Lon)) :- event(Event), rdf_has(Event, sem:hasPlace, Place), rdf_has(Place, wgs84:lat, literal(type(xsd:decimal, LatText))), rdf_has(Place, wgs84:long, literal(type(xsd:decimal, LonText))), atom_number(LatText, Lat), atom_number(LonText, Lon).
Tip: you can re-open a file or predicate in the editor using the command edit/1. Below are some examples. The system asks you to select the right item if multiple items match the query.
?- edit(demo). % edit the file demo ?- edit(event_point). % edit the predicate event_point
Prolog rules with resource arguments
The Prolog compiler transforms resource arguments of the form <prefix>:<local> to the global id form at compile time. When you write Prolog rules with resource arguments, you must identify the resource arguments arguments via the rdf_meta/1 declaration.
:- rdf_meta my_rule(?, r). my_rule(SomeArg, SomeResource) :- ..., rdf_has(SomeResource, sem:Place, Place), ... .
In the two exercises below, you are asked to write two predicates. Add
these predicates to the file
demo.pl and add them to the export
list of this module.
- Write a predicate
event_in_box(Event, Lat1, Lon1, Lat2, Lon2)that finds all events inside a box bounded by a given latitude and longitude range. The Netherlands is roughly bounded by Lat 51..54 and Lon 2..8 degrees. Use your predicate to find all events in this box.
- Actor types (i.e., ship types) are organised in a hierarchy. Write
event_actor_type(Event, ActorType)that finds all events in which a given type of actor (ship) is involved. Your predicate must also show events that are labeled with (transitive) subtypes of the given type. An example query is:
?- event_actor_type(Event, poseidon:atype_passenger_vessel).
You are now ready to Serve a web page.