Prolog - Write out facts and reading a users input - prolog

I am quite new to Prolog and have had some trouble understanding it.
I have some facts named 'problem' I wish to first print out these facts to the user and then ask them to input a value, this value is then read and used later.
From my understanding thus far, it would be best to use a forall to print out these facts and then use read to read the value inputted, but I am having some issue implementing this. Here is what I have so far, any explanation would be appreciated
My question: How do I read in the input from the user regarding the problem and apply that into a variable for later use?
tellMeYourProblem:-
forall(problem(P),
writeln(P)),
answer = read(X),
problem('1').
problem('2').
problem('3').
problem('4').
problem('5').
problem('6').
problem('7').
problem('8').
problem('9').
problem('10').

Note: This answer uses SWI-Prolog.
How do I read in the input from the user regarding the problem?
You are doing that already with read(X), however read/1 reads terms (terms end with periods) and you probably want to read characters. If you are using SWI-Prolog take a look at Primitive character I/O for reading characters and Predicates that operate on strings for reading strings.
How do I apply that into a variable for later use?
When doing basic I/O with a user at a text level, a REPL is a good way to start. Adding a REPL is a bit more complicated so I will give you the code.
tellMeYourProblem :-
output_problems,
read_input.
output_problems :-
forall(problem(P),
writeln(P)).
read_input :-
repeat,
read_string(user_input, "\n", "\r\t ", _, Line),
process_input(Line).
process_input(Line) :-
string(Line),
atom_number(Line, N),
integer(N),
do_something_with(Line),
fail.
process_input("quit") :-
write('Finished'), nl,
!, true.
do_something_with(X) :-
writeln(X).
problem('1').
problem('2').
problem('3').
problem('4').
problem('5').
problem('6').
problem('7').
problem('8').
problem('9').
problem('10').
Also with Prolog, the style is to use snake casing so tellMeYourProblem should be tell_me_your_problem.
Normally in Prolog a REPL is done with ->/2, (Read Input till quit statement Prolog) , but I changed this to add more guard statements so that the exit condition would work, e.g.
string(Line),
atom_number(Line, N),
integer(N)
or putting the guard in the head, e.g.
process_input("quit")
When doing I/O to a screen and keyboard, the thought is to use stdIn and stdOut but for the keyboard SWI-Prolog uses user_input instead. See: Input and output
After all of the boiler plate code for the REPL is the next part you seek which is to do something with the input value, in this case just print it out.
do_something_with(X) :-
writeln(X).

The easiest to write out the facts of problem/1,
is to use the builtin listing/[0,1]. This builtin
accepts a so called predicate indicator. You can
write out the facts via:
?- listing(problem/1).
The predicate is supported by many Prolog systems
such as GNU Prolog, etc.. For how to read input see
for example the post by Guy Coder.

Related

How to iterate through the predicates in Prolog

I'm new to prolog, but basically, I want a program to iterate through the predicates(not sure if I'm using that term correctly) and then come to a final predicate which can process the input and provide one of two answers. The ask and the maplist were my tries at iterating through the program the way a program like Java would.
(Also, sidenote, but is there any way to have the user input Yes and No instead of true. and false.?)
Here's how my code looks currently:
ask(happy,X).
ask(lonely,X).
ask(education,X).
ask(institution,X).
ask(home,X).
ask(parents,X).
ask(social_life,X).
ask(hobbies,X).
ask(opinion,X).
ask(relationship,X).
ask(finances,X).
ask(future,X).
ask(freedom,X).
ask(feelings,X).
maplist(ask(_), Xs).
Xs= [happy(X),lonely(X),education(X),institution(X), home(X),
parents(X), social_life(X), hobbies(X), opinion(X), relationship(X),
finances(X), future(X), freedom(X),feelings(X)].
happy(X):-
write("Are you happy?"),nl,
read(X).
lonely(X):-
write("Are you lonely?"),nl,
read(X).
Maybe this can serve as inspiration
main(AnswersOut) :-
Ls = [happy,lonely,education],
ask_next_question(Ls,[],AnswersOut).
ask_next_question([L|Ls],Answers,AnswersOut) :-
format("Question about: ~w\n",[L]),
read_line_to_string(user_input,Str),
format("You said: ~w\n",[Str]),
ask_next_question(Ls,[L-Str|Answers],AnswersOut).
ask_next_question([],A,A).
Then you can collect answers into a list of pairs for further processing.
Note the use of read_line_to_string/2 which doesn't read a term (necessarily terminated with .) as read/2 does, but an arbitrary String terminated by newline.
Run it:
?- main(A).
Question about: happy
|: Well....
You said: Well....
Question about: lonely
|: Yes
You said: Yes
Question about: education
|: Too high
You said: Too high
A = [education-"Too high", lonely-"Yes", happy-"Well...."].

Using the prolog format predicate to print to file

Is it possible to use the prolog format predicate to print to file?
I have a table of data that I print to stdout using the format predicate, i.e.
print_table :-
print_table_header,
forall(range(1.0,10.0,0.1,N), print_row(N,L)).
%% print_row(L) :- take a list of the form, [a,b,c,d,e] and
%% print it to screen as a single row of tab separated float values (1DP)
print_row(N,L) :-
build_row(N,L),
format('~t~1f~10+ ~t~1f~10+ ~t~1f~10+ ~t~1f~10+ ~t~1f~10+ ~n', L).
print_table_header :-
format('~t~w~10+ ~t~w~10+ ~t~w~10+ ~t~w~10+ ~t~w~10+ ~n', ['N','N2','N3','N4','N5']).
would be nice to somehow reuse the code to print the same thing to file.
In addition to the other good answer (+1!), I would like to present a purer solution to such tasks.
The key idea is to make format/2 accessible within DCGs, and then to use a DCG to describe the output.
This is very easy, using the codes argument of format/3, provided by several Prolog implementations. All you need are the following short auxiliary definitions:
format_(Data, Args) --> call(format_dlist(Data, Args)).
format_dlist(Data, Args, Cs0, Cs) :- format(codes(Cs0,Cs), Data, Args).
The nonterminal call//1 calls its argument with two additional arguments that let you access the implicit DCG arguments, and this is used to describe additional codes via format/3.
Now, we can simply use the nonterminal format_//2 within DCGs.
For example, to describe a simple table:
table -->
row([a,b,c]),
row([d,e,f]).
row(Ls) --> format_("~t~w~10+~t~w~10+~t~w~10+~n", Ls).
Usage example and result:
?- phrase(table, Cs), format("~s", [Cs]).
a b c
d e f
Cs = [32, 32, 32, 32, 32, 32, 32, 32, 32|...].
Note that one last remaining format/2 is used to actually write the output to the screen.
However, everything else is free of side-effects and declaratively describes a table.
An important advantage of this method is that you can easily write test cases to see whether your tables are (still) correctly formatted. It is easy to reason about Prolog lists of codes (described with a DCG), but quite hard to reason about things that only appear on the terminal.
You can!
Consider the following extract of the SICStus Prolog documentation for format/[2,3]:
11.3.85 format/[2,3]
Synopsis
format(+Control, +Arguments)
format(+Stream, +Control, +Arguments)
Interprets the Arguments according to the Control string and prints the result on Stream.
The predicates format/[2,3] are widely supported across Prolog implementations.
However, as of right now, these predicates are not part of ISO Prolog.
I would write the output 'routines' with an additional parameter, a Stream, and then I would pass user while testing or printing to screen. See ISO predicates open/3, close/1 etc for stream handling...
Note that IO it's among the least 'declarative' areas of the language, because, for efficiency, an approach based on side effects is required...
SWI-Prolog has a builtin with_output_to, that would allows to reuse your existing code without adding a parameter. But since you tagged iso-prolog your question, you should really add the Stream parameter...

Read the whole fact from external file

According to the below when try to assert the fact I have type error callable expected , I think the insertion o facts line by line happens successfully.But,the asserta does not work well.Despite that,I tried to convert to string using ( string_codes(?String, ?Codes) ) or insert as line of code but it does not success
start:-
writeToFile,
readFromFile,
usereduc(C,D),
writef(C),
writef(D).
writeToFile:-
writef('What is your Name'),nl,
read(Name),
writef('What is your country'),nl,
read(Country),
writef('What is your education'),nl,
read(Education),
open('output.txt',write,Out),
write(Out,usercountry(Name,Country)),nl(Out),
write(Out,usereduc(Name,Education)),
close(Out).
readFromFile:-
open('output.txt',read,In),
repeat,
read_line_to_codes(In,X),nl,
readfactsFromfile(X),asserta(X),
close(In).
readfactsFromfile(end_of_file).
readfactsFromfile(X):-
writef(X),
string_codes(S, X),
asserta(S),!,
fail.
You are trying to write and then read back Prolog terms. For this you should use the combination write_term/3 and read_term/3.
Since read/1 requires you to add a dot to the end of the input term, I have added the option fullstop/1 to write_term/3. The working code then looks as follows:
:- dynamic(usereduc/2).
start:-
writeToFile,
readFromFile,
usereduc(C,D),
writef(C),
writef(D).
writeToFile:-
writef('What is your Name'),nl,
read(Name),
writef('What is your country'),nl,
read(Country),
writef('What is your education'),nl,
read(Education),
setup_call_cleanup(
open('output.txt',write,Out),
(
write_term(Out,usercountry(Name,Country), [fullstop(true)]),nl(Out),
write_term(Out,usereduc(Name,Education), [fullstop(true)])
),
close(Out)
).
readFromFile:-
setup_call_cleanup(
open('output.txt',read,In),
(
repeat,
read_term(In, X, []),
readfactsFromfile(X),asserta(X), !
),
close(In)
).
readfactsFromfile(end_of_file):- !.
readfactsFromfile(X):-
asserta(X),!,
fail.
Notice that I have added the following additional improvements to your code:
* The declaration of usereduc/2 as a dynamic predicate. If this is left out Prolog complains that the predicate does not exists, since it is asserted at run time.
* Removed unwanted determinism using the cut ! at two spots.
* Use of setup_call_cleanup/3 to ensure that opened streams get closed even if the operations performed on the stream are buggy.
Notice that the code is still non-deterministic, giving you the same result twice. This is due to the code asserting the same terms twice.
Hope this helps!
This is a good example where code-injection can be exploited in Prolog without proper care.
My name is 'a,b).\n:- initialization(dobadthings). %'. So output.txt will look like
usercountry(a,b).
:- initialization(dobadthings). %whatevercountry).
userreduc(a,whatevere).
The built-in predicate read/1 accepts full Prolog syntax.
Unfortunately, the analogon to read/1 is not write/1, nor writeq/1 (which is close) but rather:
write_term(T, [quoted(true)]).
Additional options like variable_names/1 may help in a specific situation where variable names should be retained.
Another (potential) problem is the usage of the idiosyncratic writef/1 which seems to be unique to SWI and does some specific interpretation of certain characters. In any case, not a good idea to use. A simple write/1 would be of same value.

Defining predicates in SICStus Prolog / SWI-Prolog REPL

I am reading http://cs.union.edu/~striegnk/learn-prolog-now/html/node3.html#subsec.l1.kb1,
but I am having trouble running the following predicate:
SICStus 4.0.1 (x86-win32-nt-4): Tue May 15 21:17:49 WEST 2007
| ?- woman(mia).
! Existence error in user:woman/1
! procedure user:woman/1 does not exist
! goal: user:woman(mia)
| ?-
If, on the other hand, I write it to a file and run consult the file, it seems to work fine...
Am I only allowed to define predicates in a file having later to consult them? Can't I just do it in the editor itself?
It's a little annoying to make predicates in the repl. You could do
| ?- ['user'].
woman(mia).
^D
ie consult user input, or
| ?- assertz(woman(mia)).
assert it. Both awkward IMO -- there might be a better way, though, I just don't know it. In general it is easier to use a script.
You should enter woman(mia). into a file to assert it as a fact. If you write it into the interpreter, it's taken as a query, not a fact.
From the SWI Prolog FAQ:
Terms that you enter at the toplevel are processes as queries, while
terms that appear in a file that is loaded into Prolog is processed as
a set of rules and facts. If a text reads as below, this is a rule.
carnivore(X) :- animal(X), eats_meat(X).
Trying to enter this at the toplevel results in the error below. Why?
Because a rule is a term :-(Head, Body), and because the toplevel
interprets terms as queries. There is no predicate with the name :-
and two arguments.
?- carnivore(X) :- animal(X), eats_meat(X). ERROR: Undefined
procedure: (:-)/2 ERROR: Rules must be loaded from a file ERROR:
See FAQ at http://www.swi-prolog.org/FAQ/ToplevelMode.txt
Isn't this stupid? Well, no. Suppose we have a term
eats_meat(rataplan). If this appears in a file, it states the fact
that rataplan eats meat. If it appears at the toplevel, it asks Prolog
to try proving whether rataplan eats meat.
If a text reads
:- use_module(library(clpfd)).
This is a directive. Directives are similar to queries, but instead of
asking the toplevel to do something, they ask the compiler to do
something. Like rules and facts, such terms belong in files.
Instead of writing to a file you can also use assert in the toplevel (as explained later in the FAQ as well).

Prolog rule based system

Hi i have a rule based prolog system as shown below:
%forward chaining Production system
:-op(800,fx,if). %set operators for if
:-op(700,xfx,then). %then rules
:-op(300,xfy,or).
:-op(200,xfy,and).
%dynamic(....) allows predicate inside brackets fact to be asserted and retracted,
% here were are making fact (/1 means fact has 1 argument) dynamic so we can add and
% take facts from working memory.
:-dynamic(fact/1).
fact(has(smith,raisedIntraocularPressure)). %list of facts
fact(had(smith,previousHeatAttack)).
fact(has(smith,leftQuadraticPain)).
fact(is(smith,heavySmoker)).
fact(is(jones,asthmatic)).
fact(has(jones,raisedIntraocularPressure)).
fact(is(jones,heavySmoker)).
forward:-
new_fact(P),
!,
write('New fact '), write(P),nl,
asserta(fact(P)), %adds a fact to working memory
forward
;
write('no more facts').
new_fact(Action):-
if Condition then Action,
not(fact(Action)),
composedFact(Condition).
composedFact(Cond):-
fact(Cond).
composedFact(C1 and C2):-
composedFact(C1),
composedFact(C2).
composedFact(C1 or C2):-
composedFact(C1)
;
composedFact(C2).
print:-
if has(Person,riskOfHeartAttack) and has(Person,previousHeartAttack)
then need(Person,digitalis).
if has(Person,leftQuadraticPain) and has(Person,highBloodPressure)
then has(Person,riskOfHeartAttack).
if has(Person,leftQuadraticPain)then has(Person,highBloodPressure).
if has(Person,highBloodPressure) and is(Person,heavySmoker)
then has(Person,riskOfHeartAttack).
if is(Person,asthmatic) and has(Person,riskOfHeartAttack) and has(Person,previousHeatAttack)then give(Person,preminolv).
not(X):-
X,!,fail;true.
Okay first off i need it to create a command that prints the list of facts in the databases.
Secondly each rule is only used once. I need to change the code so that all the relevant facts are used. Apparently this can be done using a "bagof" function but i have no idea how to use it.
Thanks in advance =D
Print the list of facts:
print_facts :-
findall(F, fact(F), Facts),
maplist(writeln, Facts).
The findall/3 metapredicate is also the key to your second question, although you can also use bagof. See documentation, tutorial.

Resources