translate(list1, list2) in prolog - prolog

I was trying a functor translate([3,5,1,3],[three,five,one,three]) which does the operation of printing numbers. I get a strange warning while executing like this,
35 ?- translate([1,2,3],[a,b,c]).
ERROR: write/2: stream `a' does not exist
domains
list1=integer*
list2=symbol*
predicates
translate(list1,list2)
means(integer,symbol)
clauses
translate([],[]).
translate([],_):-
write("\nError in Input").
translate(_,[]):-
write("\nError in Input").
translate([Head1|Tail1],[Head2|Tail2]):-
write(Head2," = "),
means(Head1,Name),
write(Name,"\n"),
translate(Tail1,Tail2).
means(0,zero).
means(1,one).
means(2,two).
means(3,three).
means(4,four).
means(5,five).
means(6,six).
means(7,seven).
means(8,eight).
means(9,nine).
What exactly is the problem? This is the expected value.
translate([1,2,3],[a,b,c])
a = one
b = two
c = three
Yes

Variables need to be uppercase:
translate([1,2,3],[A,B,C]).
When you enter the translate([Head1|Tail1],[Head2|Tail2]) clause, a unifies with Head2, and then you try to satisfy write(Head2, "="), which is write(a, "=").
write/2 takes as first argument a Stream and writes the second argument to that Stream.
Presumably you want to use - if you want output at all - something like
writef('Head2 = %w', [Head2])
(I got the formatting from here.)

Related

Prolog setOf with Multiple Predicates

In my prolog database, I have below facts:
played('Sharon rose', piano).
played('Robert Kay', piano).
played('Kelvin Cage', drums).
singer('Robert Kay').
band_leader('Sharon rose').
I want to print out all the names uniquely as a single list.
Below is my query using setof and the output:
setof(X, (played(X,_);singer(X);band_leader(X)), Output).
Output = ['Robert Kay','Sharon rose'] ? ;
Output = ['Kelvin Cage'] ? ;
Output = ['Robert Kay','Sharon rose']
yes
However, the output isn't what I want.
I want it to print out the names uniquely as a list.
You get multiple answers due to the anonymous variable in the goal argument of setof/3. Try instead:
?- setof(X, Y^(played(X,Y);singer(X);band_leader(X)), Output).

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.

Prolog: How to read data from console and store into database. Getting errors

update :-
write("Name?:"),
read(Name),
assert(Name),nl,
write("Age?:"),
read(Age),
assert(Age),
write("Continue(y or n)?:"),
read(Respond),
process(Respond).
process(y) :-
write('Name?:'),
read(Name),
assert(Name),nl,
write("Age?:"),
read(Age),
assert(Age),
repeat,
write("y or n"),
read(Respond),
process(Respond).
process(n) :- !.
I want to run this Prolog to assert in the name and age, but when I write age for the number, it shows
?- update.
Name?:fred.
Age?:|: 25.
ERROR: Type error: `callable' expected, found `25' (an integer)
ERROR: In:
ERROR: [9] assert(25)
ERROR: [8] update at c:/example.pl:11
ERROR: [7] <user>
?-
How to figure out this problem.
Problem 1
Incorrect input for assert/1
The problem is not with just Age it is with any input that uses assert, e.g.
?- update.
Name?:Fred
|: .
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] assert(_4940)
ERROR: [8] update at c:/example.pl:8
ERROR: [7] <user>
?- update.
Name?:Jim.
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] assert(_5826)
ERROR: [8] update at c:/example.pl:8
ERROR: [7] <user>
The problem is that assert/1 is not being given a fact or rule.
assert/1 says:
Assert a clause (fact or rule) into the database.
See facts and rules
In the example above Fred is not a fact because it does not end with a period (.).
In the example above with Jim. a period was given but because Jim starts with a capital letter, it is not a fact or rule but a variable.
When the age is entered as a number, again this is not a fact or rule it is an integer.
Problem 2
Use of read/1 which says:
Read the next Prolog term from the current input stream and unify it with Term.
When reading a Prolog term the input must end with a period.
This not only requires the input to be a term, but end with a . which is even more confusing given the prompt, e.g Age. Most of the examples you find do what you did, the corrected code below does what you want.
Problem 3
Competing ways or repeating.
The code is using two ways:
Use of repeat/0
It is recursive, e.g.
process(y) :-
...
process(Respond).
This is making it hard to get the code working.
Problem 4
Duplicate code, e.g.
write("Name?:"),
read(Name),
assert(Name),nl,
write("Age?:"),
read(Age),
assert(Age),
write("Continue(y or n)?:"),
read(Respond),
process(Respond).
Duplicated code is more likely to lead to problems when one copy is corrected and the other copy is not corrected.
Problem 1 fix
Make the input a fact before storing in the database with assert/1, e.g.
Values in variables
Name
Age
Variables converted to facts by adding a functor
name(Name)
age(Age)
The facts used with assert/1
assert(name(Name))
assert(age(Age))
Problem 2 fix
Use read_string/5, e.g.
read_string(user, "\n", "\r", End, Name)
This reads the input into the variable Name as a string. Now that the input is a string, and not a Prolog term, the period is no longer required. There are predicates that operate on strings.
Problem 3 fix
Use the recursion form and remove repeat/0.
This could also use repeat/0 instead of recursion. The corrected code below uses recursion to demonstrate the change to process/1.
Problem 4 fix
Just refactor the code. You can see this in the corrected code at the end.
Now with the fixes in place.
Change 1
Since the input for continue is no longer a term, e.g. y or n, but a string, the parameter for process needs to be a string, e.g.
process("y") :-
process("n") :-
Change 2
Age will be asserted as a string but would be better asserted as an integer.
number_string/2 can solve this, e.g.
number_string(Age_n,Age),
assert(age(Age_n))
Change 3
user27815 Asked in a comment:
do you need the cut in process("n") :- !. ?
Since
process(Respond).
is not creating a choice point, the cut is not needed.
Corrected code:
update :-
% Respond will be read as a string and not as a term, so it needs "".
process("y").
process("y") :-
write('Name: '),
read_string(user, "\n", "\r", End, Name),
assert(name(Name)),
write("Age: "),
read_string(user, "\n", "\r", End, Age),
number_string(Age_n,Age),
assert(age(Age_n)),
write("Continue: (y or n) "),
read_string(user, "\n", "\r", End, Respond),
process(Respond).
process("n").
Example run:
?- update.
Name: Fred
Age: 30
Continue: (y or n) y
Name: Jim
Age: 21
Continue: (y or n) n
true.
To check that the database was updated use listing/1
?- listing(name/1).
:- dynamic name/1.
name("Fred").
name("Jim").
true.
?- listing(age/1).
:- dynamic age/1.
age(30).
age(21).
true.
A free enhancement.
Keeping the facts of name and age separate doesn't keep the relation between them intact. A better solution would be a person fact with both Name and Age values.
Here is the necessary modified code.
update :-
% Respond will be read as a string and not as a term, so it needs "".
process("y").
process("y") :-
write('Name: '),
read_string(user, "\n", "\r", End, Name),
write("Age: "),
read_string(user, "\n", "\r", End, Age),
number_string(Age_n,Age),
assert(person(Name,Age_n)),
write("Continue: (y or n) "),
read_string(user, "\n", "\r", End, Respond),
process(Respond).
process("n").
Example run:
?- update.
Name: Fred
Age: 30
Continue: (y or n) y
Name: Jim
Age: 21
Continue: (y or n) n
true.
To check that the database was updated use listing/1
?- listing(person/2).
:- dynamic person/2.
person("Fred", 30).
person("Jim", 21).
true.
After noticing your deleted answer.
In your deleted answer you have
?- person(name(N), age(A)).
N = nancy,
A = 22;
N= steve,
A = 100;
true.
The change needed for this variation of the fact to be created is
assert(person(name(Name),age(Age_n)))
however that might not be the optimal way to go.
In Prolog, positions typically indicate the meaning of a value, e.g. first position is name and second position is age. In this variation by adding the functors name and age to the fact person/2 you are duplicating known knowledge, but more importantly the possibility the amount of work Prolog has to do.
For example:
If the fact was person(Name,Age). to get at Name and Age Prolog only needs one unification. But with person(Name,Age). Prolog now needs to unify with person(name(nancy),age(22)) then to get Name has to unify again with name(nancy) and to get Age has to unify with age(22). You could also use person(name(Name),age(Age)). which requires only one unification, but now makes your code more verbose.
When first learning Prolog this crutch helps, but when working with larger data sets, this starts to impact performance.
Another item of note in your deleted answer is that the names of the people are still based on using read/1, e.g. nancy and steve. While a lot of Prolog examples do this, there is no requirement to keep them as such, they can be strings. Odds are the code will never need to exactly match on nancy or steve and instead will always reference them as a value in a variable. The nice thing about keeping them as strings is that when writing them out, they will appear correctly as Nancy and Steve.
This is because assert does not work on variables. It asserts a fact or rule; in other words, assert(something) asserts that something must be true.
From the SWI-Prolog documentation:
Assert a clause (fact or rule) into the database.
An integer value is not a rule or a fact. It is (in this case) an integer, not something that evaluates to a boolean value. There's no point in asserting a value.
I would write some helpers:
read_assert(P,V) :- format('~w ? ',[P]), read(V), A =.. [P,V], assert(A).
?- maplist(read_assert, [name,age], Vs).
name ? capellic.
age ? 99.
Vs = [capellic, 99].
?- name(N).
N = capellic.

Prolog programm returns yes instead of value

I got the following event: item(C,X,G,P), (where C is a number for the product,X it's name,G it's price,P it's cost).
When i use the command item(n3001,_,_,P) directly on the prolog console i get as answer
G = 1.25 X = 100 but when i write the equation p3(C)-: item(C,_,_,P). then i consult the text i get as answer yes.
My question clarified is how come the one time i get the value of P which i want and the other time i get whether it's true or false?
There are no return values in Prolog and p3/1 does not constitute a function but a relation. Your definition
p3(C) :-
item(C,_,_,P).
reads: If item(C,_,_,P) succeeds then p3(C) succeeds as well. For the sake of argument, let's assume that your code includes the following fact:
item(n3001,100,1.25,1).
If you query
?- p3(n3001).
Prolog unifies C in the head of your rule with n3001 and then tries your goal item(C,_,_,P) which succeeds. Hence the rule succeeds and Prolog tells you:
?- p3(n3001).
yes
If you want to know the price corresponding to n3001 you have to to define a rule where P appears in the head of the rule as well, e.g.:
p3(C,P) :-
item(C,_,_,P).
If you query that you'll get to see the value of P corresponding to n3001:
?- p3(n3001,P).
P = 1
If you query item/4 directly P appears in the arguments and therefore you get to see a substitution for it that satisfies your query:
?- item(n3001,_,_,P).
P = 1

String comparison program in swi-prolog always fails

I'm trying to write a program using swi-prolog that randomly asks people for their first or last name and prints "correct" or "incorrect" based on what they type. The current correct answers are "Hello" and "World" but regardless of what the user types, the output is false and correct/incorrect isn't printed.
start:-(Q=['What is your first name?','What is your last name?'],
random_member(N,[0,1]),
nth0(N,Q,X),
writeln(X)),
readln(S),
check_answer(N,S).
check_answer(N,S):-A=['Hello','World'],
nth0(N,A,X),
writeln(X),
(S=#=X)->writeln('correct'),
not(S=#=X)->writeln('incorrect').
I later edited it to:
start:-(Q=['What is your first name?','What is your last name?'],
random_member(N,[0,1]),
nth0(N,Q,X),
writeln(X)),
read(S),
check_answer(N,S).
check_answer(N,S):-A=['Hello','World'],
nth0(N,A,X),
writeln(X),
writeln(S),
((S=#=X))->writeln('correct') ; writeln('incorrect').
I can spot two problems in your code.
a) readln/1 (undocumented) returns a list of items (then peek the first item or use read/1):
?- readln(X).
|: Hello.
X = ['Hello', '.'].
?- readln(X).
|: Hello
X = ['Hello'].
?- readln(X).
|: Hello .
X = ['Hello', '.'].
b) The pair of if then else operator (->) will always fail, because you omit the else branch on both, and the conditions are exclusives. Try
...
((S=#=X)->writeln('correct') ; writeln('incorrect')).
edit there are 2 problems. I wrongly suggested read/1. That read a Prolog term, and then read a variable if we write a variable, i.e. a UppercaseStartingSymbol. My fault. readln seems ok then, but change the pattern to select the first item.
Another problem, unrelated: you misplaced the closed parenthesis in -> 'statement'.
Here the code:
start:-(Q=['What is your first name?','What is your last name?'],
random_member(N,[0,1]),
nth0(N,Q,X),
writeln(X)),
readln(S),
check_answer(N,S).
check_answer(N,[S|_]):-A=['Hello','World'],
nth0(N,A,X),
writeln(X),
writeln(S),
((S=#=X)->writeln('correct') ; writeln('incorrect')).

Resources