---+ 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 Run =|?- 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 =demo= 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 the file =|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 : 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), ... . == ---++ Exercises 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. 1. 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. 2. Actor types (i.e., ship types) are organised in a hierarchy. Write a predicate 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][PiratePage.txt]]. @see [[Tutorial index][Piracy.txt]]