Words with repeating symbols in prolog v5.2 - prolog

I need to write prolog predicate that reads file and creates a list of words with repeating symbols. For example from text:
A dog and an apple and a pipe.
the result should be:
['apple', 'pipe']
I wrote this:
domains
file_ = f
s=string
c=char
i=integer
list=s*
list1=c*
predicates
str_a_list(s,list)
readfile(s,s)
example(s)
write_symbols(list1)
search(list1,list1,list1)
check(list)
str_list(s,list1)
search1(list1,c,i,i)
clauses
readfile(S,N):-existfile(N),!,
openread(F,N),
readdevice(F),file_str(N,S).
str_a_list("",_):-!.
str_a_list(" ",_):-!.
str_a_list(S,[H|T]):-fronttoken(S,H,S1),
str_a_list(S1,T).
search1([],_,I,I):-!.
search1([H|T],H,I,M):-I1=I+1,search1(T,H,I1,M).
search1([H|T],X,I,M):-H<>X,search1(T,X,I,M).
search([],_,_):-!.
search([H|T1],L,L0):-search1(L,H,0,M),M>=2,write_symbols(L0).
search([_|T],L,L0):-search(T,L,L0).
write_symbols([]):-write(" "),!.
write_symbols([H|T]):-write(H),write_symbols(T).
str_list("",[]).
str_list(S,[H|T]):- frontchar(S,H,S1),str_list(S1,T).
check([]):-!.
check([H|T]):-str_list(H,L),search(L,L,L),check(T).
example(Y):-readfile(S,Y),str_a_list(S,L),check(L).
goal
write("Enter file name: "),
readln(Y),example(Y).
It's giving me this error:
This flow pattern doesn't exist openread(o,i)
on line:
openread(F,N)

I tried computing this prolog task, maybe you may find something useful in my solution that may help you with yours. I've written my code using basic prolog:
First: The first predicate separates the sentence into words. I have used the built-in function split_string.Example: "The dog" will become "The","dog".
g(B):-
split_string(B,' ','', L),
d(L).
Second: In the second predicate, we split each word into a separate list of characters. Example: "dog" will become ["d","o","g"].
stringsplit(A,L1):-
atom_chars(A, L1).
Third: Then check each list if it contains doubles. the base case predicate tell to stop when get empty brackets. The checkdouble second predicate checks if a character is in the remaining list (using member). If yes then load the character in List R. Else, don't load the character in R.
checkdouble([],[]):-!.
checkdouble([H|T],[H|R]):-
member(H,T),
checkdouble(T,R).
checkdouble([],[]).
checkdouble([H|T],List):-
\+member(H,T),
checkdouble(T,List).
Fourth: By this point you will have a number of list: empty and those containing duplicates from each word. Example: For [bat] [apple] [polo] we will get [][p][o].
So now we use a predicate that simply prints the list of words that have doubles ignoring those words with no doubles i.e [].
s(_,B):-
B=[].
s(D,B):-
B\=[],
write(D).
Finally: Putting the code together:
g(B):-
split_string(B,' ','', L),
d(L).
d([]).
d([H|T]):-
stringsplit(H,K),
checkdouble(K,R),
s([H],R),
d(T).
s(_,B):-
B=[].
s(D,B):-
B\=[],
write(D).
checkdouble([],[]):-!.
checkdouble([H|T],[H|R]):-
member(H,T),
checkdouble(T,R).
checkdouble([],[]).
checkdouble([H|T],List):-
\+member(H,T),
checkdouble(T,List).
stringsplit(A,L1):-
atom_chars(A, L1).
Example:
?-g("A dog and an apple and a pipe").
OUTPUT:
[apple][pipe]
1true
false
?-g("Two funny little red apples fell from a tree one day").
OUTPUT:
[funny][little][apples][fell][tree]
1true
false
?-g("On a hill upon the grass there sits a squirrel in the chill").
OUTPUT:
[hill][grass][there][sits][squirrel][chill]
1true
false

Related

Checking if all elements of list are same data type (atom I guess). Prolog

I am a total beginner in Prolog. I have some custom types: bird, animal and fish. I want to pass a list to a function like so areSameType([owl, eagle, chicken]). and get a result if the whole list is type bird or animal or fish. For example:
areSameType([owl,giraffe,shark]). > false
areSameType([owl,eagle,chicken]). > true
areSameType([cat,mouse,giraffe]). > true
The data I have inserted is:
bird(owl).
bird(eagle).
bird(chicken).
animal(cat).
animal(mouse).
animal(giraffe).
fish(shark).
fish(magikarp).
fish(gyarados).
I have tried with this function:
isSameType(X,Y):- bird(X),bird(Y);animal(X),animal(Y);fish(X),fish(Y).
areSameType([H1,H2|T]):- isSameType(H1,H2), areSameType([H2,T]).
But the problem is I don't have a criteria to check if H2 is the last element of the list or maybe I got it all wrong with this logic.
There are two problems here with your areSameType/1 predicate:
there is no stop condition: in case the list is empty, or contains exactly one element, than all the items in the list have the same type; and
you need to recurse with [H2|T] (notice the pipe |, instead of the comma ,).
So we can fix this with:
areSameType([]).
areSameType([_]).
areSameType([H1,H2|T]):-
isSameType(H1,H2),
areSameType([H2|T]).
We can however use maplist/2 [swi-doc] here, and write this predicate without recursion (well no recursion in the areSameType/1 predicate itself), like:
areSameType([]).
areSameType([H1|T]) :-
maplist(isSameType(H1), T).

Prolog, print employees with same names

This is my first time using Prolog.
I have employees:
employee(eID,firstname,lastname,month,year).
I have units:
unit(uID,type,eId).
I want to make a predicate
double_name(X).
that prints the last names of the employees with the same first name in the unit X.
I am doing something like this :
double_name(X) :-
unit(X,_,_eID),
employee(_eID,_firstname,_,_,_),
_name = _firstname,
employee(_,_name,_lastname,_,_),
write(_lastname).
But it prints all the employees in the unit.
How can i print only the employees with the same name ?
unit(unit_01,type,1).
unit(unit_01,type,2).
unit(unit_01,type,3).
employee(1,mary,smith,6,1992).
employee(2,fred,jones,1,1990).
employee(3,mary,cobbler,2,1995).
double_name(Unit) :-
unit(Unit,_,Eid_1),
employee(Eid_1,Firstname,Lastname_1,_,_),
unit(Unit,_,Eid_2),
Eid_1 \= Eid_2,
employee(Eid_2,Firstname,Lastname_2,_,_),
write(Firstname),write(","),write(Lastname_1),nl,
write(Firstname),write(","),write(Lastname_2).
Variables in Prolog typically start with an upper case letter, but starting them with and underscore is allowed, but not typical.
In double_name/2 the predicates like
unit(Unit,_,Eid_1)
employee(Eid_1,Firstname,Lastname_1,_,_)
are used to load the values from the facts into variables while pattern matching (via unification) that the bound variables match with the fact.
To ensure that a person is not compared with themselves.
Eid_1 \= Eid_2
and to make sure that two people have the same first name the same variable is used: Firstname.
The write/1 and nl/0 predicates just write the result to the screen.
Example:
?- double_name(unit_01).
mary,smith
mary,cobbler
true ;
mary,cobbler
mary,smith
true ;
false.
Notice that the correct answer is duplicated. This can be resolved.
See: Prolog check if first element in lists are not equal and second item in list is equal
and look at the use of normalize/4 and setof/3 in my answer
which I leave as an exercise for you.

Prolog build rules from atoms

I'm currently trying to to interpret user-entered strings via Prolog. I'm using code I've found on the internet, which converts a string into a list of atoms.
"Men are stupid." => [men,are,stupid,'.'] % Example
From this I would like to create a rule, which then can be used in the Prolog command-line.
% everyone is a keyword for a rule. If the list doesn't contain 'everyone'
% it's a fact.
% [men,are,stupid]
% should become ...
stupid(men).
% [everyone,who,is,stupid,is,tall]
% should become ...
tall(X) :- stupid(X).
% [everyone,who,is,not,tall,is,green]
% should become ...
green(X) :- not(tall(X)).
% Therefore, this query should return true/yes:
?- green(women).
true.
I don't need anything super fancy for this as my input will always follow a couple of rules and therefore just needs to be analyzed according to these rules.
I've been thinking about this for probably an hour now, but didn't come to anything even considerable, so I can't provide you with what I've tried so far. Can anyone push me into the right direction?
Consider using a DCG. For example:
list_clause(List, Clause) :-
phrase(clause_(Clause), List).
clause_(Fact) --> [X,are,Y], { Fact =.. [Y,X] }.
clause_(Head :- Body) --> [everyone,who,is,B,is,A],
{ Head =.. [A,X], Body =.. [B,X] }.
Examples:
?- list_clause([men,are,stupid], Clause).
Clause = stupid(men).
?- list_clause([everyone,who,is,stupid,is,tall], Clause).
Clause = tall(_G2763):-stupid(_G2763).
I leave the remaining example as an easy exercise.
You can use assertz/1 to assert such clauses dynamically:
?- List = <your list>, list_clause(List, Clause), assertz(Clause).
First of all, you could already during the tokenization step make terms instead of lists, and even directly assert rules into the database. Let's take the "men are stupid" example.
You want to write down something like:
?- assert_rule_from_sentence("Men are stupid.").
and end up with a rule of the form stupid(men).
assert_rule_from_sentence(Sentence) :-
phrase(sentence_to_database, Sentence).
sentence_to_database -->
subject(Subject), " ",
"are", " ",
object(Object), " ",
{ Rule =.. [Object, Subject],
assertz(Rule)
}.
(let's assume you know how to write the DCGs for subject and object)
This is it! Of course, your sentence_to_database//0 will need to have more clauses, or use helper clauses and predicates, but this is at least a start.
As #mat says, it is cleaner to first tokenize and then deal with the tokenized sentence. But then, it would go something like this:
tokenize_sentence(be(Subject, Object)) -->
subject(Subject), space,
be, !,
object(Object), end.
(now you also need to probably define what a space and an end of sentence is...)
be -->
"is".
be -->
"are".
assert_tokenized(be(Subject, Object)) :-
Fact =.. [Object, Subject],
assertz(Fact).
The main reason for doing it this way is that you know during the tokenization what sort of sentence you have: subject - verb - object, or subject - modifier - object - modifier etc, and you can use this information to write your assert_tokenized/1 in a more explicit way.
Definite Clause Grammars are Prolog's go-to tool for translating from strings (such as your English sentences) to Prolog terms (such as the Prolog clauses you want to generate), or the other way around. Here are two introductions I'd recommend:
http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse29
http://www.pathwayslms.com/swipltuts/dcg/

Prolog, how to show multiple output in write()

go :- match(Mn,Fn),
write('--Matching Result--'),
nl,
write(Mn),
write(' match with '),
write(Fn),
match(Mn1,Fn1).
person(may,female,25,blue).
person(rose,female,20,blue).
person(hock,male,30,blue).
person(ali,male,24,blue).
match(Mn,Fn):-person(Fn,'female',Fage,Fatt),
person(Mn,'male',Mage,Matt),
Mage>=Fage,
Fatt=Matt.
Hi,this is my code...but it's only can show the 1 output...but there are 3 pair of matching in match(X,Y).how to show them all in my go function.
Thank you
You get all your matches if you force backtracking, usually by entering ; (e.g. in SWI Prolog). But you also see that you are getting unnecessary outputs true. This is because the last clause in go is match(Mn1,Fn1). This clause succeeds three times and binds the variables Mn1,Fn1 but then only true is output, because you do not write() after that clause. The fourth time match(Mn1,Fn1) fails and by backtracking you come back to the first clause match(Mn,Fn) that matches, the match is output, etc.
You surely do not want to have this behavior. You should remove the last clause match(Mn1,Fn1) in go. Now by pressing ; you get the 3 matches without any output true in between.
But what you likely want is that the program does the backtracking. To achieve this, you just need to force backtracking by adding false as the last clause. To get proper formatting of the output, use the following program. The last clause go2. is added to get true at the very end.
go2 :- write('--Matching Result--'), nl,
match(Mn,Fn),
write(Mn), write(' match with '), write(Fn), nl,
fail.
go2.
This technique is called failure driven loop.
If you have any predicate that has multiple results and want to to find all of them, you should use findall/3
For example, in your case, you could do something like:
findall([X,Y], match(X,Y),L).
L will be a list that will contain all the X,Y that satisfy match(X,Y) in the format [X,Y].
for example, assuming that:
match(m1,f1).
match(m2,f2).
the result will be L = [ [m1,f1], [m2,f2] ]
note that you can define the format as you wish, for example you could write:
findall(pair(X,Y), match(X,Y), L).
L = [ pair(m1,f1), pair(m2,f2) ]
findall( X, match(X,Y), L).
L = [ m1, m2]
findall( 42, match(X,Y), L).
L = [42, 42]
then you have to recurse on the list to print them.
However, if you wish to find one result, run some code and then continue you could use forall/2:
forall(match(X,Y), my_print(X,Y).
Prolog is a lazy language. Which means that it will stop once it has found a condition that made your problem true. This will be the very first match alone.
IF your code is working (I haven't tried it), then you should try and run the match-statement like this in your prolog inspector: match(X,Y)
The prolog inspector will return all states and print them for you.

Illegal start of term in Prolog

I'm trying to write some predicates to solve the following task (learnprolognow.com)
Suppose we are given a knowledge base with the following facts:
tran(eins,one).
tran(zwei,two).
tran(drei,three).
tran(vier,four).
tran(fuenf,five).
tran(sechs,six).
tran(sieben,seven).
tran(acht,eight).
tran(neun,nine).
Write a predicate listtran(G,E) which translates a list of German number words to the corresponding list of English number words. For example:
listtran([eins,neun,zwei],X).
should give:
X = [one,nine,two].
I've written:
listtran(G,E):- G=[], E=[].
listtran(G,E):- G=[First|T], tran(First, Mean), listtran(T, Eng), E = [Mean|Eng).
But I get the error: "illegal start of term" when compiling. Any suggestions?
The last bracket in your last line should be a square one.
Also, you might want to make use of Prolog's pattern matching:
listtran([], []).
listtran([First|T], [Mean|EngT]):-
tran(First, Mean),
listtran(T, EngT).

Resources