Prolog menu prompt doesn't print properly - prolog

I made a menu that compile without error, but has a strange behavior. It's supposed to ask three time for different input, but it only show 2 different prompt.
The goal of the number 1 choice of the menu is to read from the user input the name , the price and the year of the car, and than adding it to the database.
Here is the code:
menu :- write('-- Menu --'),nl, write('0. Quit'), nl, write('1. Add a car'), nl, read(X), pick(X).
pick(0) :- write('The end.'),nl.
pick(1) :-
write("Name:"),
read_line(N),nl,
write("Price :"),
read_line(P),nl,
write("Year :"),
read_line(Y),nl,
assertz(car(N,P,Y)),
menu.
:- dynamic car/3.
car(blue1,2000, 2012 ).
car(blue2,1000, 2006).
car(red1,2000, 2010).
read_line(String) :-
current_input(Input),
read_string(Input, "\n", "\r", _, String).
What is wrong with this code? I tried to decompose the predicate and only use read_string , but I get the same result.
EDIT: While the accepted answer solved my first issue, I still have issues with my program.

You have to put the stuff given to write/1 in quotes:
write('Price :')
or
write("Price :")
so that it is interpreted as a "element of text".
The "element of text" can then be mapped to a Prolog 'atom' or maybe, in SWI-Prolog, an SWI-Prolog 'string'.
If the text only contains alphanumerics and begins with a lowercase letter, there is no need to quote it to get a Prolog atom directly.
?- atom('foo').
true.
?- atom(foo).
true.
?- atom('foo bar baz').
true.
?- atom(foo bar baz).
ERROR: Syntax error: Operator expected
ERROR: atom(foo
ERROR: ** here **
ERROR: bar baz) .

I found the solution if anyone is having a similar issue. You need to add ,nl after the write(X) for it to print properly.

Related

Prolog - program skipping over read?

Title more or less says it all. I got the following code in SWI-PROLOG:
get_card(1):-
nb_getval(playerOneHand, Hand),
write("Select which cards you want to play:"), nl,
read(Input),
handle_input(Input).
get_card(2):-
nb_getval(playerTwoHand, Hand),
write("Select which cards you want to play:"), nl,
read(Input),
handle_input(Input).
Expected input-format right now is something like [ 0, 1 ]. to play your first two cards, [ 0 ]. to only play your first card, so on and so forth. While I know this is beyond horrible as far as input formats go, the priority right now is to atleast get it working, then move on to a better UI from there.
This is what happens:
I'm very new to Prolog so bear with me, but this is how I'm looking at it: It seems to be "skipping" over our read and is now expecting a new command to be entered instead (ENTER has been pressed in the above picture).
I feel like the solution should be very simple but unfortunately is nothing I can seem to wrap my head around. Thanks in advance!
EDIT: Example code that can be ran to reproduce the issue, unless it's only happening on my system for some reason:
% Initialize globals
?- nb_setval(playerOneHand, []).
?- nb_setval(playerTwoHand, []).
handle_input(Input, Hand):-
write("Input is "), write(Input), nl,
write("Hand is "), write(Hand), nl.
get_card(1):-
nb_getval(playerOneHand, Hand),
write("Select which cards you want to play: "), nl,
read(Input),
handle_input(Input, Hand).
get_card(2):-
nb_getval(playerTwoHand, Hand),
write("Select which cards you want to play: "), nl,
read(Input),
handle_input(Input, Hand).
?- write("Player 1: "), get_card(1), nl,
write("Player 2: "), get_card(2), nl.
Using SWI-Prolog and the given code in a test.pl file, it is simply consulted via the terminal interface (File -> Consult -> test.pl). Trying to give SWI-Prolog ANY kind of input then results in the issue at hand.
As mentioned by Isabelle Newbie in the comments, swipl.exe (that is started by default) has a long-running bug associated with proper input/output. Navigating to where Prolog is installed and instead using swipl-win.exe seems to have done the trick.

SWI-PL: read() after a writeln() / write(),nl holds out the output of all previous write()

I'm trying to make a prolog menu in which the script asks the user to enter some data, so it's all a chain of write(), read(), nl and maybe some writeln().
The problem is that for some reason the read() function holds out the output of the write until all the reads finish. That is a problem becasue all those writes are telling the suer what to enter.
I made a test code for showing what happens, because my actual project is a mess:
test:-
write("X is "),
read(X),
writeln("Y is "),
read(Y),
writeln("Z is "),
read(Z),
write([X,Y,Z]).
This what I expect:
?- test.
X is
|: 1.
Y is
|: 2.
Z is
|: 3.
[1,2,3]
true.
But this is what I get:
?- test.
1.
|: 2.
|: 3.
X is Y is Z is [1,2,3]
true.
SWI is threaded, 64 bits, version 7.6.4, and I'm in KDE Neon 5.16.2 (Based on Ubuntu 18.04, kernel 4.15.0-54
You might want to use flush_output/0 after the write/1, like this:
test:-
write("X is "), flush_output,
read(X),
writeln("Y is "), flush_output,
read(Y),
writeln("Z is "), flush output,
read(Z),
write([X,Y,Z]).
But I actually cannot reproduce your problem. With exactly your code, without any flushing, I see on my terminal:
?- test.
X is 1.
Y is
|: 2.
Z is
|: 3.
[1,2,3]
true.
So, we see different things. Why?
We have different versions of SWI-Prolog on different OSs?
You don't type exactly the same things as I type?
Difficult to say. But make sure to read the documentation of flush_output/0, there might be a clue there of what is going on.

Prolog - 'unknown clause' error message when asking for user input when using PIE (Prolog Interface Engine)

I'm writing code for a simple program that outputs any phrase that the user inputs. Here's my code so far:
input():-
read(X),
nl,
write(X).
Here's the output:
input().
input().
Unknown clause found read(X$0)
Execution terminated
No solutions
Here's my desired output:
input().
input().
hello
hello
Note: In a comment the OP noted this was originally done using PIE (Prolog Interface Engine)
Your problem is that you are using read/1 which expects a Prolog term. Prolog terms are not strings that can be of any form, Prolog terms end with a period (.). So in your example input(). works because it ends with a period, hello does not work because it does not end with a period.
Using your query
?- input().
|: input().
and entering input(). works
input()
true.
?- input().
|: hello
|: .
entering hello does not work right away as indicated by the second prompt |: but then entering the . completes the Prolog term and works.
hello
true.
--
Here is demo of your code, slightly modified running on SWISH.
When I ran your code with SWI-Prolog installed on my laptop it worked with input() as the predicate. When I tried the same with SWISH it complained, but changing the predicate from input() to input solved that problem.
Now knowing that you are not using a common Prolog such as SWI-Prolog and seeing the error message
Unknown clause found read(X$0)
tells me that PIE does not have read/1, I did a quick check of some tutorials for PIE and could not find any use of read/1. The obvious conclusion is that PIE does not support read/1 and if you want to use read/1 while learning Prolog you will have to use something that does, e.g. SWI-Prolog, SWISH, GNU Prolog

Prolog Returning Elements Within Facts to The User

I have a Prolog knowledge base with some "symptom" facts called facts.pl. Here is an example of my KB:
symptom("Typhoid", "muscle_pain").
symptom("Typhoid", "bloating").
symptom("Meningitis", "headache").
symptom("Meningitis", "fever").
symptom("Meningitis", "stiff neck" ).
symptom("Measles", "cough").
symptom("Measles", "runny_nose").
I have written a short prolog program in another file called "diseaseSearch.pl". This program consults facts.pl and is supposed to allow the user to enter a disease name and prints the disease's corresponding symptoms to the screen.
My code:
:- write('loading disease database'), nl.
:- [facts].
:- write('disease database loaded'), nl, nl.
getsymptoms:-
write('> Enter a diseae name followed by a period.'), nl,
write('For Example: Measles'), nl,
write('Disease Name?:'),
read(Input), nl,
symptom(Input,Output),
write(Output).
If I enter "Measles." the output should be "cough" and "runny_nose". However, with the code above no matter which disease I enter it always returns the result from the first fact which is "muscle_pain". SWI output found here
I found a similar method from an online tutorial, I am trying to learn the basics of Prolog input and output right now. Am I on the right track? Some tips to solve this problem would be greatly appreciated!
I guess you are entering Measles without " " and prolog takes it as a variables. Either you should enter it with "". If you enter Measles then it's a variables but if you enter "Measles" then it's a term.
If you want to enter without annotations then you need to make a database in which you have all terms(means that they start with small letter) then you don't need annotation.

Prolog read predicate cant read user key in in initialization?

I want to have a prolog program which can auto run once I compile finish and it should read input from user keyboard. However when i use
:- write('Your name is: '), nl, read(X).
there is not any effect on read(X), which it means that there us not any prompt for users to key in. Is there any solution for this problem? My prolog compiler is WIN-Prolog 5.0, thanks for your helo :)
maybe you need something like
:- initialization(main). % changed to be ISO compliant, was :- initialization main.
main :- write('Your name is: '), nl, read(X).
at least, ISO Prologs do it in this way....
Since read/1 is meant to parse Prolog (it's a full fledged parser), you must supply a Prolog term, and don't forget, as Joel76 suggested, to complete input with a dot: for instance:
Your name is:
|: 'Carlo'.

Resources