setof
The built-in Prolog predicate setof(+Template, +Goal, -Set)
binds Set
to the list of all instances of Template
satisfying the goal Goal
.
For example, given the facts and rule:
happy(fido). happy(harry). happy(X) :- rich(X). rich(harry).
it follows that
?- setof(Y, happy(Y), Set). Y = _G180 Set = [fido, harry] ; false.
Notice that:
harry
is happy
happy(harry).
rich(harry).
harry
only appears once in the binding for Set
;Set
is in sorted order.Compare:
?- bagof(Y, happy(Y), Bag). Y = _G180 Bag = [fido, harry, harry] ; false.
and
?- findall(Y, happy(Y), Bag). Y = _G180 Bag = [fido, harry, harry] ; false.
The differences between bagof
and findall
on the one hand, and setof
on the other hand, include the fact that with setof
, you get sorted order and no repetitions. (For differences between bagof
and findall
, see findall.)
setof
will fail (and so not bind Set
) if the there are no instances of Template
for which Goal
succeeds - i.e. effectively it fails if Set
would be empty. bagof
also fails in these circumstances, while findall
does not (it binds the variable that is its third argument to the empty list, or, if the third argument is instantiated, it succeeds if the third argument is the empty list).
side-effects
Prolog is supposedly a declarative language - that is, one which specifies relationships between concepts using facts and rules and then uses a logic engine to answer queries that relate to those facts and rules, typically by finding bindings for variables that allow queries to succeed.
However, in "real" Prolog, there are built-in predicates that do no comform to this pattern. These include input-output "predicates" like see
, seeing
, seen
, tell
, telling
, told
, write
, nl
, prin
, print
, put
, and read
, get
, get_byte
, flush_output
. All of these predicates succeed or fail independent of any logicalaspect of the problem being solved - normally, in fact, they will succeed unless there is an error relating to the external input/output system - e.g. it may not be possible to read from a file because the user does not have permission to access the file, or because the file does not exist.
Even more extra-logical are assert
, asserta
, assertz
and retract
, retractall
, which even change the program that is running.
Side-effects take Prolog programs out of the world of strict logic (as does the cut, which changes the way the inference engine operates in solving a query). Programs with side-effects are harder to analyse that programs without side-effects. The practical impact of side-effects on the understandabilty of Prolog programs depends on how they are used. For example, using memoisation to record facts inferred in order to save re-calculation is probably harmless, but using assert
to create new rules might in some cases make debugging a program next to impossible. Use side-effects with care.
singleton variables
SWI Prolog sometimes produces an warning message like this:
% cat example.pl happy(Pet) :- dog(Pet), walkies(Oet). % prolog -s example.pl Warning: example.pl:1: Singleton variables: [Oet] ...
This is alerting you to the fact that the variableOet
has only been used once in the rule it appears in. Such variables are often (but not always) spelling mistakes. In this case, Oet
should have been Pet
.
Sometimes singleton variable reports are caused by the programmer trying to write helpful, readable code, like this version of member
:
member(Item, [Item | Rest]). member(Item, [NotItem | Rest]) :- + Item = NotItem, member(Item, Rest).
Prolog would report
Singleton variables: [Rest]
for such code, because the helpfully-named variable Rest is only used once in member(Item, [Item | Rest]).
The solution is to put an underscore ( _
) at the start of this instance of Rest
, thus replacing member(Item, [Item | Rest]).
with member(Item, [Item | _Rest]).
SWI Prolog will treat _Rest
as a don't-care variable and not report it.
spy
The built-in pseudo-predicate spy
allows one to trace the execution of a query in a selective manner. If you want to find out about each time that a particular predicate is called, you spy
that predicate: see example below.
?- listing(happy). happy(A) :- rich(A). true. ?- listing(rich). rich(fred). true. ?- spy(rich). % Spy point on rich/1 true. [debug] ?- happy(fred). Call: (8) rich(fred) ? creep Exit: (8) rich(fred) ? creep Exit: (7) happy(fred) ? creep true.
As you can see, the call to rich is traced, but not much else. See also trace
, which traces the execution of everything.
Turn spying off with nospy
:
[debug] ?- nospy(rich). % Spy point removed from rich/1 true.
static
A Prolog procedure is static if its facts/rules do not change during the execution of the program of which they are part. This is the default: most Prolog procedures are static. The opposite of static is dynamic.
structures
Structures in Prolog are simply objects that have several components, but are treated as a single object. Suppose that we wish to represent a date in Prolog - dates are usually expressed using a day, a month, and a year, but viewed as a single object. To combine the components into a single structure, we choose a functor, say date
, and use it to group the components together - for the date usually expressed as 21 March 2004, we would probably write
date(21, mar, 2004)
Note that the order of the components is our choice - we might have instead written date(2004, mar, 21)
The choice of functor is arbitrary, too.
The components between the parentheses are referred to as arguments. Thus in the date example, the arguments are 21
, mar
, and 2004
.
Structures may be nested, too - the following example groups a name and a date, perhaps the person's date of birth:
persondata(name(smith, john), date(28, feb, 1963))
This term has two arguments, the first being name(smith, john)
and the second being date(28, feb, 1963)
See also Bratko, section 2.1.3.