How can I reuse a Prolog data structure? - prolog

I am writing a small program using Prolog. There is a data structure that I want to reuse, so I tried assigning it to a variable:
CitizenProfile = voter_profile(citizen,not_in_prison).
Then I used it like this:
state(alabama, [CitizenProfile]).
However, I am encountering this error when I compile my file from the console:
**[No permission to modify static_procedure `(=)/2'][1]**
==
I even tried declaring the equal sign dynamic, but that didn't solve anything. :(
:- dynamic (=)/2.

The reason for the error is that it looks to Prolog like you're trying to do this:
=(CitizenProfile, voter_profile(citizen,not_in_prison)).
This looks just like any other fact definition. =/2 could just as easily be foobar/2:
foobar(CitizenProfile, voter_profile(citizen,not_in_prison)).
Now, if we were in the middle of some rule body, this might be a legitimate way to establish a variable binding. Then everything would be culminating in this:
foo :- ...,
CitizenProfile = voter_profile(citizen,not_in_prison),
state(alabama, [CitizenProfile]).
That would be the same as saying this:
foo :- ...,
state(alabama, [voter_profile(citizen,not_in_prison)]).
If this expansion is what you're trying to accomplish, there is unfortunately no way to create shorthand in a fact database like this. You could, as #hardmath says, use assertz/1 to accomplish it, which would look like this:
make_database :-
CitizenProfile = voter_profile(citizen,not_in_prison),
assertz(state(alabama, [CitizenProfile])).
This would be kind of sketchy behavior though, because you're putting static information into the dynamic store. In my experience, one doesn't usually want to build up large structures in the database. It's usually cleaner and easier to build several relations and "join" across them in a relational manner. I'm not sure what all you're going to want here, so this is just a sketch, but this is kind of what I'd expect to see:
voter_profile(voter1, alabama, citizen, not_in_prison).
voter_profile(voter2, alabama, citizen, in_prison).
voter_profile(voter3, new_mexico, citizen, not_in_prison).
rather than what I presume you'd be building (eventually), which I picture more like this:
state(alabama, [voter_profile(citizen,not_in_prison), voter_profile(citizen, in_prison)]).
state(new_mexico,[voter_profile(citizen,not_in_prison)]).
The temptation to create a bunch of lists is understandable, but Prolog's database can't really help you with processing them. You'll wind up resorting to a lot of member/2 and O(N) searching which will add up to pretty bad performance. By default, Prolog will index on the first argument, but each implementation defines some indexing declarations you can use to make it index the second or Nth arguments in addition or instead. You can then use bagof/3 or findall/3 to reconstitute the lists if you need all the results.

Probably what you want is to define a dynamic predicate voter_profile/2 and assertz new facts "dynamically" to be remembered by that predicate store (the clause database). I say "probably" because you haven't made it clear how a state (e.g. Alabama) should be related to a particular citizen profile.
See here for the SWI-Prolog builtin assertz/1 documentation and much more on database mechanisms of SWI-Prolog.

Related

SWI-prolog semweb library processing of URI

Being new to prolog I am reading existing code (as well as trying to write some code). Having some prior background in semweb I started to play with it and see something that is confusing me. Example assertion:
?- rdf_assert(ex:bob, rdf:type, foaf:'Person').
I also did find the following in the documentation:
Remember: Internally, all resources are atoms. The transformations
above are realised at compile-time using rules for goal_expansion/2
provided by the rdf_db library
Am I correct in assuming that somehow the library is treating the three URIs as atoms? I thought that the compiler would treat this as module_name:predicate, but that does not seem to be the case. If that is true, could you please provide a simple example on how this could be done in prolog?
Thanks
Prolog is not a functional language. This implies 2+3 does not evaluate to 5 and is just a term that gets meaning from the predicate that processes it. Likewise, ex:bob is just a term that has no direct relations to modules or
predicates. Only predicates such call/1 will interpret this as "call bob in the module ex".
Next to that, (SWI-)Prolog (most Prolog's, but not all) have term expansion that allows you to rewrite the term that is read before it is handed to the compiler. That is used to rewrite the argument of rdf/3: each appearance of prefix:local is expanded to a full atom. You can check that by using listing/1 on predicates that call rdf/3 using the prefix notation.
See also rdf_meta

Storing variables as a list in prolog

I've been searching around a bit for way to store variables as a list for future use in different methods. So say one method produces X, another method has one produces Y and so on, I don't know if there is a way to declare a list, append each variable to that list and than call it at the to output everything I've saved in it.
Hope this makes sense. Any help would be great, thanks
You can use assert/1 to store things, like
assert(data(100))
then you can just say
data(X)
later to get X = 100
It sounds like what you want is to have each module call assert with a different predicate.
You can use lists also, but it will probably not be better in any way.
Addition: it is customary in this situation to use predicate names that are unlikely to be used in the interpreter, e.g. ones containing spaces, as in
assert('My Data from Module X'(100,200,300))

Is it acceptable for a prolog procedure to work only one way?

I have a prolog program:
link(liverpool,preston).
link(liverpool,manchester).
link(preston,lancaster).
link(preston,manchester).
link(lancaster,carlisle).
link(lancaster,leeds).
link(carlisle,leeds).
link(manchester,leeds).
%checks to see if X is in the supplied list
inlist( X, [X|_]).
inlist( X, [_|Ys]) :- inlist( X, Ys).
merge([],L,L).
merge([H|T],BList,CList):-
inlist(H,BList),
merge(T,BList,CList).
merge([H|T],BList,[H|CList]):-
merge(T,BList,CList),
not(inlist(H,BList)).
Merge works if I call it like this:
merge([a,b,c],[d,e,f],Result). --> [a,b,c,d,e,f]
or more importantly, what it was designed to solve:
merge([a,b,c],[a,d,e,f],Result). --> [a,b,c,d,e,f]
but if I call merge like this:
merge(X,[d,e,f],[a,b,c,d,e,f]).
There is a stack overflow. Is this generally acceptable behavior for a function that is designed to work one way? Or is there some convention that functions should work in both ways?
Edit: merge works if you call it like this:
merge([a,b,c],X,[a,b,c,d,e,f]). --> [d,e,f]
First, you should not call these "functions". "Predicates" is the correct term.
It's generally desirable for Prolog predicates to work "both ways". But it's not always possible or worth the effort in a particular situation.
To inform about ways a predicate is intended to be used mode-declarations can be used. These declarations conventions are different from system to system. These declarations are mostly serve as a documentation for programmers and rarely used by compilers, but can be used by testing frameworks and other helper tools.
Examples of conventions for mode declarations:
SWI-Prolog: http://www.swi-prolog.org/pldoc/man?section=modes
ECLiPSe CLP: http://eclipseclp.org/doc/applications/tutorial003.html#toc10 (scroll to 2.7.3 Mode declaration)
Also there is a convention (described in "The Craft of Prolog", for example) that input parameters of a predicate come first, output parameters come last.

How do I reinstate constraints collected with copy_term/3 in SICStus Prolog?

The documentation says that
copy_term(+Term, -Copy, -Body) makes a copy of Term in which all
variables have been replaced by new variables that occur nowhere
outside the newly created term. If Term contains attributed
variables, Body is unified with a term such that executing Body
will reinstate equivalent attributes on the variables in Copy.
I'm previously affirming numerical CLP(R) constraints over some variables, and at some point I collect these constraints using copy_term/3. Later, when I try to reinstate the constraints using 'call(Body)', I get an "Instantiation error" in arguments of the form [nfr:resubmit_eq(...)]
Here's a simplified example that demonstrates the problem:
:-use_module(library(clpr)).
{Old>=0, A>=0,A=<10, NR= Old+Z, Z=Old*(A/D)}, copy_term(Old,New,CTR), call(CTR).
Results in:
Instantiation error in argument 1 of '.'/2
! goal: [nfr:resubmit_eq([v(-1.0,[_90^ -1,_95^1,_100^1]),v(1.0,[_113^1])])]
My question is: how do I reinstate the constraints in Body over New? I haven't been able to find concrete examples.
copy_term/3 is a relatively new built-in predicate, that has been first introduced in SICStus about 2006. Its motivation was to replace the semantically cumbersome call_residue/2 which originated from SICStus 0.6 of 1987 by a cleaner and more efficient interface that splits the functionality in two:
call_residue_vars(Goal, Vars) which is like call(Goal) and upon success unifies Vars with a list variables (in unspecified order) that are attached to constraints and have been created or affected in Goal.
copy_term(Term, Copy, Body) like copy_term/2 and upon success unifies Body with a term to reinstate the actual constraints involved. Originally, Body was a goal that could be executed directly. Many systems that adopted this interface (like SWI, YAP) however, switched to use a list of goals instead. This simplifies frequent operations since you have less defaultyness, but at the expense of making reinstating more complex. You need to use maplist(call,Goals).
Most of the time, these two built-in predicates will be used together. You are using only one which makes me a bit suspicious. You first need to figure out which variables are involved, and only then you can copy them. Typically you will use call_residue_vars/2 for that. If you are copying only a couple of variables (as in your exemple) you are effectively projecting the constraints on these variables. This may or may not be your intention.
This is simply a bug in CLPR, which is unsupported. We lost touch with the CLPR supplier a long time ago.

How can I change a Prolog Database to be dynamic?

I have the following Database which connects streets via switches:
For Example
switch(r2,w52=s).
switch(w52=s,w53=d).
How can it be determined algorithmically, not through explicit deposit in a data base.??
Any suggestions?
You have several options to create and consult dynamically-generated facts in Prolog.
The basic one is to use meta-predicates such as assert and retract. There predicates add and remove facts from the program. E.g., assert(switch(w52=s,w53=d)) will add a switch clause to your program. You have to declare :- dynamic switch/2. in advance. The downside of using assert is that it does not backtrack. That is, if you asserted some fact in some predicate and it backtracked, the fact is not automatically cleaned up.
Another option is to accumulate these facts inside a list, and then use member/2 or memberchk/2 to check if a given fact is in that list, instead of querying the program. E.g.:
L = [switch(w52=s,w53=d), switch(w53=d,w54=d), ...]
member(switch(w53=A, w54=B), L) % Unifies A=d, B=d
Unlike using assertions, this method will work like any other Prolog predicate.
Finally, you can run a two-phase program. During the first phase, print to a file the terms you calculated and want to serve as facts. That's easy because Prolog supports writing complete terms, no need to format them yourself. Afterwards just consult the file. If you read the facts more often than generate them, this is the most efficient method, since Prolog will compile your file.

Resources