Prolog program- implementing rules and list matching - list

I am trying to write a program in Prolog that would recognize 'is a' statements and apply the transitive property in inquired. For example:
Input: Mary is a girl.
Output: ok.
Input: A girl is a human.
Output: ok.
Input: Is Mary a human?
Output: yes.
Here's my code:
begin :-
begin(Input).
begin(Input) :-
write('Begin.. '),
write('\n'),
readln(Input),
tokenize_atom(Atom, List),
rules(List).
begin.
rules(['A', Subj, is, a, What]) :-
asserta(a(Subj, What)),
write('ok'),
write('\n').
rules([Subj, is, a, What]) :-
asserta(is(Subj, What)),
write('ok'),
write('\n').
rules(['Is', Subj, a, What]) :-
(is(Subj, Z) ; a(Z, What)) -> (write('Yes.'), nl)
; (write('Unknown.'), nl).
It doesn't go into any of the cases, it will just say true and terminate when given a statement. What am I doing wrong?

Prolog itself wants to help you. Look at the helpful messages you get:
|: begin :-
|: begin(Input).
Warning: user://1:9:
Singleton variables: [Input]
This is pointing out that this rule is no different from:
begin :- begin(_).
This is highlighting that the role of Input in begin/1 is ambiguous. Is it input or output? If you can use it like this, it must be output, and that's consistent with how it's used in its definition, but look at the other problem you have there:
|: begin(Input) :-
|: write('Begin.. '),
|: write('\n'),
|: readln(Input),
|: tokenize_atom(Atom, List),
|: rules(List).
Warning: user://1:14:
Singleton variables: [Atom]
Where did Atom and List come from? Presumably you wanted one of those to show up from readln/1. What's actually going on here is that you're asking Prolog to input a value, which you then return, having done nothing with it; meanwhile Prolog materializes Atom and List from thin air and uses them with your rules/1 predicate. So clearly something isn't hooked up here that should be.
Then you have an obvious typo:
|: begin.
Warning: user://1:22:
Clauses of begin/0 are not together in the source-file
I suspect you meant a comma after rules(List) instead of a period.
Try fixing those problems and see if you make some progress.

Related

Prolog pattern match and return

New to Prolog here and already found it hard.
And here's the question: let's say I got a char list such as [h,e,l,l,o] and a unicode number 108(which is the letter "l").
I'm trying to write a function that take the elements of the list one by one and pattern match with the given unicode number. Once matched, return the reste of the list.
Worked on it for a whole day now , almost tried everything I can think of and I still didn't figure out how to make it work. Anyone got some ideas?
function([C|Chars], CutoffCode, Chars) :-
char_code(C, CutoffCode).
function([C|Chars], CutoffCode, Result) :-
not(char_code(C, CutoffCode)),
function(Chars, CutoffCode, Result).
e.g.
?- function([h,e,l,l,o], 108, Result).
Result = [l, o]
?- function([h,e,l,l,o], 109, Result).
false

Test in Prolog. How to run a unit test that checks if my output file matches the my text file?

I'm implementing a natural language generator using prolog (swipl).
I have a .txt test file with some of the phrases I should be able to generate in this format:
[goal,identify,type_object,animal,object,cat,event,ran away,when,[last,mont],where,[]]
[which,cats,ran away,last,month,?]
[goal,identify,type_object,animal,object,dog,event,ran,when,[last,mont],where,[]]
[which,dogs,ran away,last,year,?]
and so on...
How can I use plunit (or something else?) to check if all the elements of my test file are in my output file returning true/false?
read/1 might be what you are looking for:
Suppose I define a fact p/1:
p([a,b,c]).
then I can read a term from standard input and compare ( lines starting with |: are denoted as user input by SWI Prolog, your implementation might differ):
?- read(X), p(X).
|: [a,b,c].
X = [a, b, c].
?- read(X), p(X).
|: [].
false.

Return a list from items matching in two lists Prolog

I am very new to Prolog and I have this :
compare_list(Hours1, Hours2, Matching)
I want to return the matching hours between lists Hours1 and Hours2 into the list Matching
I can get the matches but not construct the list of matches.
Hours1 may be like: [1,2,3],
Hours2 may be like: [2,3],
So from this:
Matching Hours should be: [2,3]
Help would be appreciated.
I have implemented what Vennik has suggested and it is very near to what I want.
Results From Hours1 : [2,3,5], Hours2 : [2,5]
Give the following:
Matching = [2, 5] ;
Matching = [2] ;
Matching = [5] ;
Matching = []
Is it possible to only have the first set without producing the other three results?
You might want to consider the related question intersection and union of 2 lists.
In particular, my logically pure answer to above question might be of good use to you, as it offers multiple advantages over the code posted by #vennik above:
The predicates behave the way relations should. "Multi-directional."
They are monotone and remain sound upon arbitrary generalization / specialization.
They aim at completeness of the relation of interest, creating choice points when required.
They are efficient, avoiding the creation of useless choice points.
Try this:
compare_list([], _, []).
compare_list([Hour | Hours1], Hours2, [Hour | Matching]) :-
member(Hour, Hours2),
compare_list(Hours1, Hours2, Matching).
compare_list([_ | Hours1], Hours2, Matching) :-
compare_list(Hours1, Hours2, Matching).
Calling compare_list([1,2,3], [1,2], X), !. will result in X = [1,2].
I know that is not pure... (or not montone, if you like) ... but, if you aren't a purist, SWI-Prolog give you the predicate
intersection/3
that you can use in this way
intersection(Hours1, Hours2, Matching).

Prolog: Adding elements to list through read/1

I am trying to add user input to a list with add_read_list/2 until the word "end." is encountered. This is how the output is supposed to look:
add_read_list(Resultlist, [a,b]).
|: c.
|: d.
|: e.
|: f.
|: end.
Resultlist = [f,e,d,c,a,b].
This is how far I have come:
add_read_list(Resultlist,Entrylist) :-
read(end), append([], Entrylist, Resultlist).
add_read_list(Resultlist, Entrylist) :-
read(Input), append([Input], Entrylist, X),
add_read_list(Resultlist, X).
But this way every second input gets skipped:
add_read_list(Resultlist, [a,b]).
|: c.
|: d.
|: e.
|: f.
|: end.
Resultlist = [f,d,a,b].
What am I doing wrong?
drop the first clause, and use the simple 'if/then/else' construct:
add_read_list(Resultlist, Entrylist) :-
read(Input),
( Input = end
-> reverse(Resultlist, Entrylist)
; add_read_list(Resultlist, [Input|Entrylist])
).
instead of appending each item read, 'cons' it, and reverse the full list when done (well, simply unify to get the list in LIFO, as seems required. i.e. instead of reverse(Resultlist, Entrylist), Resultlist = Entrylist)
The actual error is read(end). This will only succeed, if the term read in is end. Otherwise it fails.
But I do have a lot of reservation to tell you this at all, since nobody every does this is Prolog. Here are the actual things that would need improvement.
The first, is to use end_of_file in place of end, because this is automatically generated at the end of a file, plus you can write it yourself, too.
The second is the way how to handle this. You need to read and then process the term read in:
... read(X), ( X == end_of_file -> ... ; /* whatever */ ... ), ....
However, please do reconsider your entire task. There is a single reason why this could be needed: When you are processing a Prolog file. But this you get cheaper and less error prone by saying [file].
So better design your data to fit into Prolog terms.

Prolog, working with multiple predicates

I've just starting working with Prolog and I don't understand how to work with multiple predicates.
For example I have to solve the following problem: Substitute in a list a value with all the elements of another list.
This is the code that I managed to write so far:
domains
elem=integer
list=elem*
predicates
%append to a list already created another list. There are 3 list parameters
%because I don't know other method
append (list,list,list)
%This will search the list (the first one) for the searched element and
%it is it will replace it with the list(the second one). The result will be
%kept in the third list.
add(list,list,elem,list)
goal
add([1,2,3,2,1],[4,5],2,L),
write (L).
clauses
add ([],[_],_,[]).
add ([A|L],L1,E,[A|L2]):-
add(L,L1,E,L2).
add ([E|L],L1,E,L2):-
add(L,L1,E,L2).
append([],[],L2).
append([],[X|L1],[X|L2]):-
append([],L1,L2).
Does your append definition is working? I think should be
append([], L, L).
append([X|Xs], Ys, [X|Zs]):-
append(Xs, Ys, Zs).
The append predicate it's one of the most basic tools in Prolog programming, better to keep the usual behaviour, or to change name...
Instead of add, a better name could be replace_elem_with_list.
To implement it you should iterate, inspecting each element, and when you find a match to what's required to replace append the list instead of copying the element.
Something like
% replace_elem_with_list(ToSearch, Replacement, SoughtElem, Result)
replace_elem_with_list([E|Es], Replacement, E, Result) :-
!, replace_elem_with_list(Es, Replacement, E, Rs),
append(Replacement, Rs, Result).
I'll leave you the other 2 cases that you will need to cover (when element doesn't match and recursion base, which are similar to append)
the result:
?- replace_elem_with_list([1,2,3,4,2,3,4],[a,b],2,L).
L = [1, a, b, 3, 4, a, b, 3, 4].