Illegal start of term in Prolog - 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).

Related

Words with repeating symbols in prolog v5.2

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

Pattern matching using list of characters

I am having difficulty pattern matching words which are converted to lists of characters:
wordworm(H1,H2,H3,V1,V2) :-
word(H1), string_length(H1,7),
word(H2), string_length(H2,5),
word(H3), string_length(H3,4),
word(V1), string_length(V1,4),
word(H3) \= word(V1),
atom_chars(H2, [_,_,Y,_,_]) = atom_chars(V1, [_,_,_,Y]),
word(V2), string_length(V2,5),
word(H2) \= word(V2),
atom_chars(H3, [_,_,_,Y]) = atom_chars(V2, [_,_,_,_,Y]).
Above this section, I have a series of 600 words in the format, word("prolog"). The code runs fine, without the atom_chars, but with it, I get a time-out error. Can anyone suggest a better way for me to structure my code?
Prolog predicate calls are not like function calls in other languages. They do not have "return values".
When you write X = atom_chars(foo, Chars) this does not execute atom_chars. It builds a data structure atom_chars(foo, Chars). It does not "call" this data structure.
If you want to evaluate atom_chars on some atom H2 and then say something about the resulting list, call it like:
atom_chars(H2, H2Chars),
H2Chars = [_,_,Y,_,_]
So overall maybe your code should look more like this:
...,
atom_chars(H2, H2Chars),
H2Chars = [_,_,Y,_,_],
atom_chars(V1, V1Chars),
V1Chars = [_,_,_,Y],
...
Note that you don't need to assert some kind of "equality" between these atom_chars goals. The fact that their char lists share the same variable Y means that there will be a connection: The third character of H2 must be equal to the fourth character of V1.

How do I Prolog specify pair printing format

Pair data is nice to work with, but I found hard to present. I ask how to accomplish printing a set of vectors such that keys & values line up in a pleasantly. Leading zeros in the pair-values, would help. Sample data:
[1-7,2-43,3-56,4-87,5-110,6-80,7-15]
[1-1837,2-1873,3-1911,4-1946,5-1975,6-1994,7-2005]
I tried to figure out use of SWI format_predicate ; but couldn't.
Then I thought to experiment inline;
format('~n~w ~w~w~n', ['Pairs: ',1-246,1-2, ' EOL']).
End result should deal with pairs of the form KK-VVVV:
01-0007 02-0043 03-0056 04-0087 05-0110 06-0080 07-0015 398 People 7 Gens.
01-1837 02-1873 03-1911 04-1946 05-1975 06-1994 07-2005 Spanning 168 Years
Final Answers:
fpair(A-B) :- format('~`0t~d~2|-~`0t~d~7| ', [A,B])
applist(_,[]). applist(P,[X|L]) :- Q =.. [P,X],call(Q),applist(P,L).
dojustone(X):- format('~# ',[fpair(X)]).
dolist(X):- applist(dolist,X).
I use a # specifier for complex formats, it allows to output specific terms. For instance
?- format('~s~n~#~n~#~n~w~n', ['Pairs: ',fpair(1-246),fpair(1-2), ' EOL']).
that is, fpair/1 is an user predicate, called by #, capturing its output.
To get fixed width fields, I use the tab specification, built from two specifiers working together. Finally, to prefix with 0s, I would use
fpair(A-B) :-
format('~`0t~d~6| ~`0t~d~12|', [A,B]).
Without knowing a priori the maximum number of digits, we must use a guess. I used 6 here.

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 constraints in a list

I have a problem in prolog which requires all possible permutations of a list of four elements(an element can be 1,2 or X) but I have to add 2 contraints to that list.The last element of it can not be the symbol "X" and the permutation can't contain the symbol "1" more than 2 times.I'm not sure where and how should I put those constraints.Can anyone give me ideeas?
domains
elem=symbol
list=elem*
predicates
elimin(elem,list,list)
perm(list,list)
clauses
elimin(H,T,[H|T]).
elimin(H,[A|T],[A|X]):-
elimin(H,T,X).
perm([],[]).
perm([H|T],X):-
perm(T,T1),
elimin(H,T1,X).
Current code:
domains
elem=symbol
list=elem*
predicates
valid(list)
generate(list)
count(list,elem,integer)
member(symbol,list)
clauses
valid(S):-
generate(S),count(S,1,C),C<2.
generate([A,B,C,D]) :-
member(A,["1","2","X"]),
member(B,["1","2","X"]),
member(C,["1","2","X"]),
member(D,["1","2"]).
member(X,[X|_]).
member(X,[_|T]):- member(X,T).
count([],_,0).
count([H|T],X,C):- H<>X,
count(T,X,C).
count([H|T],X,C1):- H=X,
count(T,X,C),
C1=C+1.
From your comment it's apparent your perm/2 is useless.
The obvious way is to join the generator with a filter accepting only valid sequences.
If the generator avoid to put a 1 in last position, it's sufficient a procedure count/3.
The generator it's easy to write with a non deterministic member/2.
Note: it's handy to keep constants lowercase (x instead of X).
valid(S) :- generate(S), count(S,1,C), C < 2.
generate([A,B,C,D]) :-
member(A,[1,2,x]),
member(B,[1,2,x]),
member(C,[1,2,x]),
member(D,[2,x]).
see if you can write count/3 by yourself...

Resources