Imagine we have the familytree module below (simple example) :
:- module(familytree, [
father/2,
mother/2,
%[...]
]).
father(X,Y) :- male(X),parent(X,Y).
father(unknown, _) :- male(unknown).
mother(X,Y) :- female(X),parent(X,Y).
mother(unknown, _) :- female(unknown).
sister(X,Y) :- female(X),parent(Z,X),parent(Z,Y), X \= Y.
%[... other relation predicates ... ]
I want to use this module predicates with different "dbs", for examples with :
:- module(familytree_xyz, []).
male(james).
male(fred).
male(mike).
female(betty).
female(sandra).
parent(james, fred).
parent(betty, fred).
Or :
:- module(familytree_simpson, []).
male(homer).
male(bart).
female(marge).
female(lisa).
parent(homer, bart).
%[...]
I need :
to choose db on runtime, not on compilation.
to use one or more dbs in same time.
to extend db, for eg. create a “familytree_simpson_extended” db module with other Simpson family members extending “familytree_simpson” db module (see above example)
to be swi-prolog compliant.
For now, I tried to play with term_expansion/2, discontiguous/1, multifile/1, dynamic/1 and thread_local/1 directives, but :
term_expansion/2 seems only usable on compile time,
discontiguous/1, multifile/1, not adapted,
dynamic dbs in prolog are seen as an “Evil” practice, however lot of packages and libraries use its (pengines, broadcast module,http lib, for examples).
thread_local/1 is not very documented and seems not often used in prolog source code (swi-prolog).
With playing with dynamic predicate, I update previous code as follow :
%familytree.pl
:- module(familytree, [
familytree_cleanup_db/0,
familytree_use_db/1,
%[... previous declarations ...]
]).
dynamic male/1, female/1, parent/2.
familytree_cleanup_db :-
retractall(male/1),
retractall(female/1),
retractall(parent/2).
familytree_use_db(ModuleName) :-
assert(male(X) :- ModuleName:male(X)),
assert(female(X) :- ModuleName:female(X)),
assert(parent(X,Y) :- ModuleName:parent(X,Y)).
%[... previous predicates ...]
And :
%main.pl
% use familytree tool predicates
:- use_module(familytree).
%load all familytree dbs at compile time.
:- use_module(familytree_xyz).
:- use_module(familytree_simpson).
:- use_module(familytree_simpson_extended).
main_xyz:-
familytree_cleanup_db,
familytree_use_db(familytree_xyz),
process.
main_simpson_all :-
familytree_cleanup_db,
familytree_use_db(familytree_simpson),
familytree_use_db(familytree_simpson_extended),
process.
process :-
findall(X, father(X,_), Xs),
write(Xs).
And it's ok to use with different db as follow :
?- main_simpson_all.
[homer,homer,abraham]
true.
?- main_xyz.
[james]
true.
So, sorry for the length of the post. Questions :
What are the criteria, pros/cons to consider with this dynamic predicates solution ? is it a good solution ?
What are the best practice / specific design pattern for prolog to do that in a clean / robust code ?**
What's about using thread_local/1 instead dynamic/1 and encapsulate call to new thread to avoid cleanup db?
Expanding my comment, the Logtalk solution is straightforward. First, define a root object with the family relations predicate:
:- object(familytree).
:- public([
father/2, mother/2,
sister/2, brother/2
]).
:- public([
parent/2,
male/1, female/1
]).
father(Father, Child) :-
::male(Father),
::parent(Father, Child).
mother(Mother, Child) :-
::female(Mother),
::parent(Mother, Child).
sister(Sister, Child) :-
::female(Sister),
::parent(Parent, Sister),
::parent(Parent, Child),
Sister \== Child.
brother(Brother, Child) :-
::male(Brother),
::parent(Parent, Brother),
::parent(Parent, Child),
Brother \== Child.
:- end_object.
Note that the lookup of the definitions of the male/1, female/1, and parent/2 starts in self, i.e. in the object, the database, that will receive the queries about the family relations. An example, derived from your sample code would be:
:- object(simpsons,
extends(familytree)).
male(homer).
male(bart).
female(marge).
female(lisa).
parent(homer, bart).
parent(homer, lisa).
parent(marge, bart).
parent(marge, lisa).
:- end_object.
An example query can be:
?- simpsons::parent(homer, Child).
Child = bart ;
Child = lisa.
You can them as many family databases as you want, load them at the same time, and define specializations of them at will. For example:
:- object(simpsons_extended,
extends(simpsons)).
male(Male) :-
^^male(Male).
male(abe).
male(herb).
female(Male) :-
^^female(Male).
female(gaby).
female(mona).
parent(Parent, Child) :-
^^parent(Parent, Child).
parent(abe, homer).
parent(abe, herb).
parent(gaby, herb).
parent(mona, homer).
:- end_object.
This solution fulfills all your requirements. SWI-Prolog is one of the supported Prolog compilers. You can install Logtalk using on of its installers. Alternatively, for SWI-Prolog, you can simply type:
?- pack_install(logtalk).
Update
In your comment to this solution, you asked about injecting a database into the family tree object logic. That's easy but it also requires a different approach. First define familytree as:
:- object(familytree).
:- public([
father/2, mother/2,
sister/2, brother/2
]).
:- public([
parent/2,
male/1, female/1
]).
:- multifile([
parent/2,
male/1, female/1
]).
father(Father, Child) :-
male(Father),
parent(Father, Child).
mother(Mother, Child) :-
female(Mother),
parent(Mother, Child).
sister(Sister, Child) :-
female(Sister),
parent(Parent, Sister),
parent(Parent, Child),
Sister \== Child.
brother(Brother, Child) :-
male(Brother),
parent(Parent, Brother),
parent(Parent, Child),
Brother \== Child.
:- end_object.
Note that is this alternative, we call male/1, female/1, and parent/2 as local predicates but they are also declared as multifile predicates. Now we need to "inject" a family database in the familytree object:
:- category(simpsons).
:- multifile([
familytree::male/1,
familytree::female/1,
familytree::parent/2
]).
familytree::male(homer).
familytree::male(bart).
familytree::female(marge).
familytree::female(lisa).
familytree::parent(homer, bart).
familytree::parent(homer, lisa).
familytree::parent(homer, maggie).
familytree::parent(marge, bart).
familytree::parent(marge, lisa).
familytree::parent(marge, maggie).
:- end_category.
Usage example (assuming familytree.lgt and simpsons.lgt files):
?- {familytree, simpsons}.
...
yes
A couple of sample queries:
?- familytree::parent(homer, Child).
Child = bart ;
Child = lisa ;
Child = maggie.
?- familytree::male(Male).
Male = homer ;
Male = bart.
?- familytree::father(Father, Child).
Father = homer,
Child = bart ;
Father = homer,
Child = lisa ;
Father = homer,
Child = maggie ;
false.
Since the source database obviously plays an important role in your use case, I suggest to make its dedicated identifier explicit in your definitions, so that it is always clear which family source you are actually referencing:
db_male(xyz, james).
db_male(simpsons, bart).
db_female(xyz, betty).
db_female(simpsons, marge).
db_parent_of(xyz, james, fred).
So, you basically have the public and multifile db_male/2, db_female/2, db_parent_of/3 predicates.
Self-contained modules can extend the existing definitions with their own source knowledge bases, made explicit in the first argument. This is where term_expansion/2 and the like may help you: Since the database name is the same within each single module, you can write expansion code that augments module-specific definitions of male/1, female/1 etc. with the suitable db argument and rewrites this to db_male/2 etc. Notice that this rewriting need only happen at compilation time. At run-time, you can supply any DB you choose as the first argument of these predicates.
It is also obvious how global definitions of female/1, male/1 may look like:
male(M) :- db_male(_, M).
Notice also that I am using names like parent_of/2 to make clear which argument is what.
assertz/1 can be used to dynamically augment each individual database when required, again supplying the name explicitly. However, for clean and robust code, I would do as much as possible at compilation time.
An alternative is the use of Prolog dicts. They have been introduced by SWI-Prolog and since release 1.3.0 they are also available in Jekejeke Prolog. If the receiver is not needed, one can simply use an underscore.
File simpson.pl:
:- module(simpson, [gender/3, parent/3]).
:- reexport(familytree).
_.gender(homer) := male.
_.gender(bart) := male.
_.gender(marge) := female.
_.gender(lisa) := female.
_.parent(homer) := bart.
_.parent(homer) := lisa.
_.parent(homer) := maggie.
_.parent(marge) := bart.
_.parent(marge) := lisa.
_.parent(marge) := maggie.
File xyz.pl:
:- module(xyz, [gender/3, parent/3]).
:- reexport(familytree).
_.gender(james) := male.
_.gender(fred) := male.
_.gender(mike) := male.
_.gender(betty) := female.
_.gender(sandra) := female.
_.parent(james) := fred.
_.parent(betty) := fred.
File familytree.pl:
:- module(familytree, [father/3]).
M.father(X) := Y :-
male = M.gender(X),
Y = M.parent(X).
To make the familytree also visible in simpson and xyz use reexport/1. This allows sending a message to simpson or xyz, but nevertheless a method from familytree will be processed. Here is an example run:
Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.19)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
?- Y = simpson{}.father(X).
Y = bart,
X = homer ;
Y = lisa,
X = homer ;
Y = maggie,
X = homer ;
false.
?- Y = xyz{}.father(X).
Y = fred,
X = james ;
false.
The exports of gender/3, parent/3, etc.. will go away with the upcoming release 1.3.1 of Jekejeke Prolog when we have made ('.')/3 call-site aware. But the result for Jekejeke Prolog is the same:
Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland
?- Y = simpson{}.father(X).
Y = bart,
X = homer ;
Y = lisa,
X = homer ;
Y = maggie,
X = homer ;
No
?- Y = xyz{}.father(X).
Y = fred,
X = james ;
No
Related
I feel really stupid, and feel like I'm missing something.
I've basically got two files:
module.pl for the universal logic rules (meant to be reusable)
state.pl one for the current scenario
In the module file (module.pl) I've declared:
inside(Food,Eater,T) :-
isTime(T),
injestEvent(InjEvent),
justAfter(T,InjEvent),
actorOfEvent(InjEvent, Eater),
objectOfEvent(InjEvent, Food).
Q1) I've had to declare all those other predicates with singleton variables (in the same file), just to stop module.pl complaining they don't exist:
isTime(_T).
justAfter(_Time,_Event).
actorOfEvent(_Event, _ActorOfEvent).
objectOfEvent(_Event,_ActorOfEvent).
Is that right?
Q2) I can't use those predicates like justAfter/2 my other file without it saying:
Local definition of user:justAfter/2 overrides weak import from module
How can I use the predicates I've imported from my module, rather redefining it?
Prolog modules were designed to hide auxiliary predicates. They don't provide a concept of interface that allows separating predicate declarations from predicate definitions. That's why the compiler complains if you export predicates that are not defined. From your description, I assume you tried something like:
----- module.pl -----
:- module(module, [
inside/3, isTime/1, injestEvent/1, justAfter/2, actorOfEvent/2, objectOfEvent/2
]).
inside(Food,Eater,T) :-
isTime(T),
injestEvent(InjEvent),
justAfter(T,InjEvent),
actorOfEvent(InjEvent, Eater),
objectOfEvent(InjEvent, Food).
---------------------
which results in:
?- [module].
ERROR: Exported procedure module:justAfter/2 is not defined
ERROR: Exported procedure module:isTime/1 is not defined
ERROR: Exported procedure module:injestEvent/1 is not defined
ERROR: Exported procedure module:objectOfEvent/2 is not defined
ERROR: Exported procedure module:actorOfEvent/2 is not defined
true.
You attempted to workaround this error by adding local definitions. But this just result in the second problem you describe. When you do something like:
?- use_module(module).
You import all the predicates exported by module, including those that you want to define in state.pl. Therefore, the compiler warns you, when loading state.pl, that this file is overriding those predicates. E.g. with:
----- state.pl -----
isTime(1).
injestEvent(injEvent).
justAfter(1, injEvent).
actorOfEvent(injEvent, eater).
objectOfEvent(injEvent, food).
--------------------
we get:
?- [state].
Warning: /Users/pmoura/Desktop/state.pl:1:
Local definition of user:isTime/1 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:2:
Local definition of user:injestEvent/1 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:3:
Local definition of user:justAfter/2 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:4:
Local definition of user:actorOfEvent/2 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:5:
Local definition of user:objectOfEvent/2 overrides weak import from module
true.
Although these are warnings and not errors, calling the inside/3 predicate will not give you what you want:
?- inside(Food,Eater,T).
true.
Where are the bindings?!? Let's trace the call to highlight the cause:
?- trace.
true.
[trace] ?- inside(Food,Eater,T).
Call: (8) module:inside(_2508, _2510, _2512) ? creep
Call: (9) module:isTime(_2512) ? creep
Exit: (9) module:isTime(_2512) ? creep
Call: (9) module:injestEvent(_2804) ? creep
Exit: (9) module:injestEvent(_2804) ? creep
Call: (9) module:justAfter(_2512, _2806) ? creep
Exit: (9) module:justAfter(_2512, _2806) ? creep
Call: (9) module:actorOfEvent(_2804, _2510) ? creep
Exit: (9) module:actorOfEvent(_2804, _2510) ? creep
Call: (9) module:objectOfEvent(_2804, _2508) ? creep
Exit: (9) module:objectOfEvent(_2804, _2508) ? creep
Exit: (8) module:inside(_2508, _2510, _2512) ? creep
true.
The trace makes it clear that the "state" predicates are being called in the wrong context.
A clean solution is to use Logtalk objects instead of Prolog modules. Logtalk extends Prolog and supports most systems, including SWI-Prolog. It supports interfaces/protocols as first-class entities (which solve the first problem you mention) and supports inheritance and calling predicates in their usage context (which solves the second problem). You could use e.g.
----- common.lgt -----
:- object(common).
:- public([
inside/3, isTime/1, injestEvent/1, justAfter/2, actorOfEvent/2, objectOfEvent/2
]).
inside(Food,Eater,T) :-
% call the next predicates in "self", i.e. in the
% object that received the inside/3 message
::isTime(T),
::injestEvent(InjEvent),
::justAfter(T,InjEvent),
::actorOfEvent(InjEvent, Eater),
::objectOfEvent(InjEvent, Food).
:- end_object.
----------------------
and then represent "state" as:
----- state.lgt -----
:- object(state, extends(common)).
isTime(1).
injestEvent(injEvent).
justAfter(1, injEvent).
actorOfEvent(injEvent, eater).
objectOfEvent(injEvent, food).
:- end_object.
---------------------
A quick test (after installing Logtalk):
$ swilgt
...
?- {common, state}.
...
true.
?- state::inside(Food,Eater,T).
Food = food,
Eater = eater,
T = 1.
As a bonus, you can define as many "state" objects as you need. You can also have default definitions for the "state" predicates in the common object. These will be inherited and used when the "state" objects don't provide a definition for a particular predicate. For example, let's add to common the clause:
objectOfEvent(injEvent, drink).
and delete (or comment out) the clause objectOfEvent(injEvent, food). from state. Save and reload and retrying the query will give you:
?- {*}. % abbreviation for Logtalk's make
% Redefining object common
...
% Redefining object state
...
true.
?- state::inside(Food,Eater,T).
Food = drink,
Eater = eater,
T = 1.
If needed, you can also dynamically create new state objects instead of defining them in source files. For example:
?- create_object(s2, [extends(common)], [], [isTime(42), ...]).
This may not be the answer you were looking for but this is also the case where the best answer is to use the right tool^H^H^H^H encapsulation mechanism for the job. Your programming pattern is also a quite common one (and one of the reasons Logtalk was developed).
It's very simple to add a basic form of 'object orientation'.
Let's say we have a clause in a module logic:
:- module(logic, [inside/4]).
% apply the rule to a specified module (expected to be a state object)
inside(M,Food,Eater,T) :-
M:isTime(T),
M:injestEvent(InjEvent),
M:justAfter(T, InjEvent),
M:actorOfEvent(InjEvent, Eater),
M:objectOfEvent(InjEvent, Food).
and we have a lot of state objects pertinent: in a file state1.pl
isTime(10).
injestEvent(eat).
justAfter(10, eat).
actorOfEvent(eat, mick).
objectOfEvent(eat, food).
and in a file state2.pl
isTime(20).
injestEvent(sleep).
justAfter(20, sleep).
actorOfEvent(sleep, everyone).
objectOfEvent(sleep, dream).
then a possible session:
?- [logic].
true.
?- s1:consult(state1).
true.
?- s2:consult(state2).
true.
?- inside(s1,Food,Eater,T).
Food = food,
Eater = mick,
T = 10.
?- inside(s2,What,Who,T).
What = dream,
Who = everyone,
T = 20.
A small generalization, worth to try:
inside(M,Food,Eater,T) :-
resolve(M),
M:isTime(T),
...
where resolve/1 could be
resolve(M) :- var(M) -> current_module(M), catch(M:isTime(_),_,fail) ; true.
this trick enable 'browsing the objects':
?- inside(M,X,Y,Z).
M = s2,
X = dream,
Y = everyone,
Z = 20 ;
M = s1,
X = food,
Y = mick,
Z = 10 ;
false.
An alternative to CapelliC is the use of Prolog dicts. They have been introduced by SWI-Prolog and since release 1.3.0 they are also available in Jekejeke Prolog. If the receiver is not needed, one can simply use an underscore.
File state1.pl:
:- module(state1, [isTime/2, injestEvent/2, justAfter/3,
actorOfEvent/3, objectOfEvent/3]).
:- reexport(logic).
_.isTime() := 10.
_.injestEvent() := eat.
_.justAfter(10) := eat.
_.actorOfEvent(eat) := mick.
_.objectOfEvent(eat) := food.
File state2.pl:
:- module(state2, [isTime/2, injestEvent/2, justAfter/3,
actorOfEvent/3, objectOfEvent/3]).
:- reexport(logic).
_.isTime() := 20.
_.injestEvent() := sleep.
_.justAfter(20) := sleep.
_.actorOfEvent(sleep) := everyone.
_.objectOfEvent(sleep) := dream.
File logic.pl:
:- module(logic, [inside/4]).
M.inside(Food,Eater) := T :-
T = M.isTime(),
InjEvent = M.injestEvent(),
InjEvent = M.justAfter(T),
Eater = M.actorOfEvent(InjEvent),
Food = M.objectOfEvent(InjEvent).
To make the logic also visible in state1 and state2 use reexport/1. This allows sending a message to state1 or state2, but nevertheless a method from logic will be processed. Here is an example run:
Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.19)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
?- T = state1{}.inside(Food,Eater).
T = 10,
Food = food,
Eater = mick.
?- T = state2{}.inside(Food,Eater).
T = 20,
Food = dream,
Eater = everyone.
The exports of isTime/2, injestEvent/2, etc.. will go away with the upcoming release 1.3.1 of Jekejeke Prolog when we have made ('.')/3 call-site aware. But the result for Jekejeke Prolog is the same:
Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland
?- T = state1{}.inside(Food,Eater).
T = 10,
Food = food,
Eater = mick
?- T = state2{}.inside(Food,Eater).
T = 20,
Food = dream,
Eater = everyone
What i am trying to do
?- string_manipulation(1\2\3,Z).
Z = 1/2/3.
?- string_manipulation(s/t/a/c/k,Z).
Z = s\t\a\c\k.
What i have tried so far
sign(/,\).
string_manipulation(Forward,Back):-
sign(Forward,_\),
; sign(/,Back).
I will be honest with you. I know this code is rubbish. I am kinda lost with this one. Just started learning Prolog, watched some videos and read some documentation but could not just find something similar to that from internet in the first look. Maybe someone could point me in some direction so i could learn the string manipulation with this one.
From the post title, and the predicate name (so called functor), seems you're looking for something like DCGs, but as an exercise in manipulation of structured terms, and operators, here is a solution for your probem:
string_manipulation(Xs, Ys) :-
member(( Xo , Yo ), [ ( / , \ ), ( \ , / ) ]),
Xs =.. [Xo, H, Xt],
Ys =.. [Yo, T, Yt],
string_manipulation(H, T),
string_manipulation(Xt, Yt).
string_manipulation(S, S) :-
atomic(S).
In SWI-Prolog, we need this preliminary declaration:
?- op(400,yfx,\).
true.
since by default
?- current_op(X,Y,/).
X = 400,
Y = yfx.
and
?- current_op(X,Y,\).
X = 200,
Y = fy.
Declaring the same precedence and associativity helps to keep things clearer.
Edit
The valuable suggestion by #mat:
string_manipulation(Xs, Ys) :-
op_replacement(Xo, Yo),
Xs =.. [Xo, H, Xt],
...
and
op_replacement(/, \).
op_replacement(\, /).
Looks like you want to replace an atom in an atom by another atom. But you would need to place quotes around the arguments, like for example '1\2\3' instead 1\2\3, otherwise the argument is not an atom but a term.
If your Prolog system has atom_split/3, you can bootstrap atom_replace/4 from it. atom_split/3 is part of Prolog Commons, and you need a bidrectional version of it. Namely you can then define:
atom_replace(Source, Old, New, Target) :-
atom_split(Source, Old, List),
atom_split(Target, New, List).
Here are some example runs. Don't worry about the backslash backslash, that is just needed to input an atom that contains a backslash. The second example using write/1 shows that it will not enter the atom:
Jekejeke Prolog 3, Runtime Library 1.3.6
?- atom_replace('1\\2\\3', '\\', '/', X).
X = '1/2/3'
?- atom_replace('s/t/a/c/k', '/', '\\', X), write(X), nl.
s\t\a\c\k
X = 's\\t\\a\\c\\k'
Here is my homework:
Let f be a file of terms. Define a procedure
findterm(Term)
that displays on the terminal the first term in f that matches the Term.
Let f be a file of terms. Write a procedure
findallterm(Term)
that displays on the terminal all the terms in f that matches the Term. Make sure that Term is not instantiated in the process (which could prevent its match with terms that occur later in the file).
I tried using cut to solve the first one
findterm(end_of_file) :- !.
findterm(Term) :-
read(Term1),
Term = Term1,
write(Term1), nl, !
;
findterm(Term).
Can anyone help me with the second?
How about the following program?
findallterm(Term, File_name) :-
open(File_name, read, Stream),
findterm(Stream, Term),
close(Stream).
findterm(Stream, _) :-
at_end_of_stream(Stream),
!.
findterm(Stream, Term) :-
read(Stream, Term_data),
( Term == Term_data
-> write( Term_data ), nl
; true
),
findterm(Stream, Term).
Input file is the following.
'c:/work/data.txt'
sun.
mercury.
sun.
mercury.
venus.
earth.
sun.
mercury.
venus.
Result
6 ?- findallterm( mercury, 'C:/work/data.txt' ).
mercury
mercury
mercury
7 ?- findallterm( venus, 'C:/work/data.txt' ).
venus
venus
I have the following input in a text file input.txt
atom1,atom2,atom3
relation(atom1 ,[10,5,2])
relation(atom2 ,[3,10,2])
relation(atom3 ,[6,5,10])
First line includes the list of atoms used in relation predicates in the file and each remaining line represents a relation predicate in order of the first line list.relation(atom1, [x,y,z]) means atom1 has a relation value of 10 with first atom, 5 with the second and 2 with the third
I need to read this file and add represent relation values for each atom seperately.For example , these are the relation values which will be added for atom1 :
assert(relation(atom1, atom1,10)).
assert(relation(atom1, atom2, 5)).
assert(relation(atom1, atom3, 2)).
I have read some prolog io tutorials and seen some recommendations on using DCG but I'm a beginner prolog programmer and having trouble to choose the method for the solving problem. So I'm here to ask help from experienced prolog programmers.
Since you didn't stated what Prolog you're using, here is a snippet written in SWI-Prolog. I attempted to signal non ISO builtins by means of SWI-Prolog docs reference.
parse_input :-
open('input.txt', read, S),
parse_line(S, atoms(Atoms)),
repeat,
( parse_line(S, a_struct(relation(A, L)))
-> store(Atoms, A, L), fail
; true ),
close(S).
:- meta_predicate(parse_line(+, //)).
parse_line(S, Grammar) :-
% see http://www.swi-prolog.org/pldoc/doc_for?object=read_line_to_codes/2
read_line_to_codes(S, L),
L \= end_of_file,
phrase(Grammar, L).
% match any sequence
% note - clauses order is mandatory
star([]) --> [].
star([C|Cs]) --> [C], star(Cs).
% --- DCGs ---
% comma sep atoms
atoms(R) -->
star(S),
( ",",
{atom_codes(A, S), R = [A|As]},
atoms(As)
; {atom_codes(A, S), R = [A]}
).
% parse a struct X,
% but it's far easier to use a builtin :)
% see http://www.swi-prolog.org/pldoc/doc_for?object=atom_to_term/3
a_struct(X, Cs, []) :-
atom_codes(A, Cs),
atom_to_term(A, X, []).
% storage handler
:- dynamic(relation/3).
store(Atoms, A, L) :-
nth1(I, L, W),
nth1(I, Atoms, B),
assertz(relation(A, B, W)).
with the sample input.txt, I get
?- parse_input.
true .
?- listing(relation).
:- dynamic relation/3.
relation(atom1, atom1, 10).
relation(atom1, atom2, 5).
relation(atom1, atom3, 2).
relation(atom2, atom1, 3).
relation(atom2, atom2, 10).
relation(atom2, atom3, 2).
relation(atom3, atom1, 6).
relation(atom3, atom2, 5).
relation(atom3, atom3, 10).
HTH
I've been tasked to implement a version of findall in Prolog without using any Prolog built-ins except for not and cut - so basically in pure Prolog.
I'm trying to search a tree for all direct descendants and return the results in a list
parent(a, b).
parent(b, c).
parent(b, d).
parent(e, d).
What I have so far is:
find(X, L) :- find2(X, [], L).
find2(X, Acc, L) :- parent(Y, X), find2(Y, [Y|Acc], L).
find2(_, Acc, Acc).
What I want to be getting when I enter for example:
find(a,X).
would be:
X = [b, c, d]
(Order not important)
However instead I am getting:
X = [b, c] ;
X = [b, d] ;
X = [b] ;
X = [].
I'm new to Prolog so any help on this would be much appreciated.
Thanks
Besides asserting data as you go, you can also use an extra-logical predicate such as nb_setarg/3. Then once a parent is found, you fail back past nb_setarg and find another parent. All previously found solutions should stay in the term you did nb_setarg on, then after all results are exhausted, the nb_setarg term is the answer. The SWI-Prolog example is good, but its just a counter. Try doing it with a list (or better yet: difference list) that builds as you go.
Take a look at this solution.
Note that this solution uses dynamic predicate named queue in order to cache all solutions until all possibilities are exhausted. Once no more solution exists, implementation retracts all facts and composes the list.
This is of course a bit simplified solution, imagine what would happen if two findall would be active at the same time. It is also a bit fragile on exact semantics of assert and retract if particular prolog implementation
Thanks for you help everyone. I managed to solve it in the end by adding a predicate which checked each item against the current list, and failed if it was already present:
find(X, Loa) :- find(X, [], Loa), !.
find(X, Acc, Loa) :- dec(X, Y), uList(Y, Acc, AccNew), find(X, AccNew, Loa).
find(_, Acc, Acc).
dec(X,Y) :- parent(X,Y).
dec(X,Y) :- parent(X,Z), dec(Z,Y).
uList(X, [], [X]) :- !.
uList(H, [H|_], _) :- !, fail.
uList(X, [H|T], L) :- uList(X, T, Rtn), L = [H|Rtn].