Prolog - How to write all prolog answers to .txt file? - prolog

man(alan).
man(john).
man(george).
list_all:-
man(X),
write(X),
fail.
Question ?-list_all gives the answer:
alan
john
george
false
So I have all the men from the database. It works! My problem: I want to get the same list, but exported to .txt file. I tried to use this code to do this:
program :-
open('file.txt',write,X),
current_output(CO),
set_output(X),
man(X),
write(X),
fail,
close(X),
set_output(CO).
The effect is: Program gives answer false and text: alan john george are not in .txt file - because of using fail predicate.
Is there an option to get all the items in the list into a .txt file (writing all options which are in database) without using fail predicate?
How can I do this? Please help me.

You're almost there. But the call to fail/0 prevents the stream to be closed. Try for example:
program :-
open('file.txt',write, Stream),
( man(Man), write(Stream, Man), fail
; true
),
close(Stream).
An alternative using the de facto standard forall/2 predicate could be:
program :-
open('file.txt',write, Stream),
forall(man(Man), write(Stream,Man)),
close(Stream).
, , ,

Related

Reading from textfile in prolog

I have some trouble with reading from text files in GNU Prolog. I want to read a .txt file and move the file to a list. I have tried to follow some previous examples on stackoverflow to read the file, but have not been able to access the file (it seems). Here is what I've got so far:
readFile:-
open('text.txt', read, File),
read_lines(File, Lines),
close(File),
write(Lines), nl.
read_lines(File,[]):-
at_end_of_stream(File).
read_lines(File,[X|L]):-
\+ at_end_of_stream(File),
read(File,X),
read_lines(File,L).
When I try to call: ?- readFile. gives me an errormessage: uncaught exception: error(syntax_error('text.txt:2 (char:1) . or operator expected after expression'),read/2).
Thanks in advance!
Edit:
As provided by David, GNU Prolog's Character input/output library and get_char worked for me!
Working code:
readFile:-
open('text.txt', read, File),
read_lines(File, Lines),
close(File),
write(Lines), nl.
read_lines(File,[]):-
at_end_of_stream(File).
read_lines(File,[X|L]):-
\+ at_end_of_stream(File),
get_char(File,X),
read_lines(File,L).
You can improve on your edit answer a bit. First note that the read_line/2 predicate name is misleading. You're reading a text file to a list of characters, not to a list of individual lines. You're also calling the at_end_of_stream/1 predicate twice and creating a spurious choice-point at each call to your read_lines /2 predicate. Moreover, the at_end_of_stream/1 predicate, albeit a standard predicate, doesn't have a reliable implementation in all Prolog systems. A possible rewrite of your code is:
read_file(File, Chars) :-
open(File, read, Stream),
get_char(Stream, Char),
read_file(Stream, Char, Chars),
close(Stream).
read_file(Stream, Char, Chars) :-
( Char == end_of_file ->
Chars = []
; Chars = [Char| Rest],
get_char(Stream, Next),
read_file(Stream, Next, Rest)
).
Now that your intent is clearer, the same functionality can be accomplished using the Logtalk reader library with a single call:
reader::file_to_chars(File, Chars)
But, if learning is is your primary goal, writing your own solutions instead of relying on existing libraries is a good choice.

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...."].

Editing Eliza chatbot in Prolog

I've been struggling trying to edit Eliza chatbot in Prolog. every time I try to edit something, a new error show up. Is it protected to any sort of editing?
I edited using SWI-prolog editor. The problem is that I'm trying to minimize the code without fully understanding it. I'm trying to do a simple short version of it. So, I might removed something essential perhaps! like "my_char_type" for example. The error I got is " retract/1: No permission to modify static procedure `rules/1'"
Is there any code for a smaller chatbot that I can understand?
Please help :'(
Prolog has a static store and a dynamic store. If you open up a file, say program.pl and you put some lines in it like this:
foo(tabitha).
foo(darlene).
those facts wind up in the static store. They're not a mutable part of your program (by default).
The asserta/1, assertz/1 and retract/1 and retractall/1 procedures form the basis of the dynamic store. If you are just sitting at the console you could just add some facts to the dynamic store and remove them by doing something like this:
?- asserta(baz(tabitha)).
true.
?- baz(X).
X = tabitha.
?- retract(baz(tabitha)).
true.
?- baz(X).
false.
However, if you are sitting at the prompt after loading program.pl and you try to retract foo(tabitha) you're going to get the static procedure message:
?- retract(foo(tabitha)).
ERROR: retract/1: No permission to modify static procedure `foo/1'
ERROR: Defined at /Users/fusion/program.pl:1
The reason is because the foo/1 facts were placed in the static store rather than the dynamic store, because you didn't put them there with asserta/1 or assertz/1 or declare the predicate as dynamic, like this:
:- dynamic foo/1.
So there are two ways forward:
Edit the program source directly and reload it.
Declare the rules/1 predicate dynamic as above.
Incidentally, reloading in SWI-Prolog is best done by running make. from the prompt.
I would recommend option #1 since otherwise it will be difficult to reconstruct your working program's state when you like what it is doing.
SWISH has the simplest Eliza ever, I have the old code below, used to test my Prolog interpreter.
here is an example session
1 ?- eliza.
? i am hungry
how long have you been hungry ?
? very long
please go on
? bye
Goodbye. I hope I have helped you
true.
SWI-Prolog tested version, ported from below ELIZA.IL (alas, SWISH is apparently missing IO primitive like read_line_from_codes, so it's simpler to paste the full code)
eliza :-
write('? '), read_word_list(Input), eliza(Input), !.
eliza([bye]) :-
write('Goodbye. I hope I have helped you'), nl.
eliza(Input) :-
pattern(Stimulus, Response),
match(Stimulus, Dictionary, Input),
match(Response, Dictionary, Output),
reply(Output),
!, eliza.
match([N|Pattern], Dictionary, Target) :-
integer(N), lookup(N, Dictionary, LeftTarget),
append(LeftTarget, RightTarget, Target),
match(Pattern, Dictionary, RightTarget).
match([Word | Pattern], Dictionary, [Word | Target]) :-
atom(Word), match(Pattern, Dictionary, Target).
match([], _Dictionary, []).
pattern([i,am,1],[how,long,have,you,been,1,'?']).
pattern([1,you,2,me],[what,makes,you,think,i,2,you,'?']).
pattern([i,like,1],[does,anyone,else,in,your,family,like,1,'?']).
pattern([i,feel,1],[do,you,often,feel,that,way,'?']).
pattern([1,X,2],[can,you,tell,me,more,about,your,X,'?']) :- important(X).
pattern([1],[please,go,on]).
important(father).
important(mother).
important(son).
important(sister).
important(brother).
important(daughter).
reply([Head | Tail]) :-
write(Head), write(' '), reply(Tail).
reply([]) :- nl.
lookup(Key, [(Key, Value) | _Dict], Value).
lookup(Key, [(Key1, _Val1) | Dictionary], Value) :-
Key \= Key1, lookup(Key, Dictionary, Value).
read_word_list(Ws) :-
read_line_to_codes(user_input, Cs),
atom_codes(A, Cs),
tokenize_atom(A, Ws).
Older code: eliza and rwl

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'.

Writing to file (Prolog)

I've been trying to loop through a list and writing it to a file, why is the following not working?
loop_through_list(List) :-
member(Element, List),
write(Element),
write(' '),
fail.
write_list_to_file(Filename,List) :-
tell(Filename), % open file to be written
loop_through_list(List),
told. % flush buffer
First, why it fails :
You use fail to provoke backtracking, which can be a good technique, but not there. Because it will make your predicate false in the end, when member has ran out of solutions. Then, once loop_through_list is false, told isn't reached and the writing isn't made properly (when I test it, the file is created but nothing is written).
If you use :
loop_through_list([]).
loop_through_list([Head|Tail]) :-
write(Head),
write(' '),
loop_through_list(Tail).
instead, it works.
But, even with this code working, you might want to use
open(Filename, write, Stream), write(Stream, Element) and close(Stream) instead of tell and told for the reasons explained in the link at the bottom of this answer.
For example :
loop_through_list(_File, []) :- !.
loop_through_list(File, [Head|Tail]) :-
write(File, Head),
write(File, ' '),
loop_through_list(File, Tail).
write_list_to_file(Filename,List) :-
open(Filename, write, File),
loop_through_list(File, List),
close(File).
or
loop_through_list(File, List) :-
member(Element, List),
write(File, Element),
write(File, ' '),
fail.
write_list_to_file(Filename,List) :-
open(Filename, write, File),
\+ loop_through_list(File, List),
close(File).
using your code and joel76 trick.
See Prolog how to save file in an existing file
It covers the same matter.
I fail to see the reason to do use this method to write a list to a file.
Programming in prolog should generally not involve loops;
besides, this is not a loop structure, it's more like a hack (or even abuse).
(and just like your case leads to unexpected bugs and problems)
Just use recursion and print the elements of the list:
write_list([]).
write_list([H|T]):-
write(H),
write(' '),
write_list(T).
more elegant and could be more efficient too.
other than that, using open/4 etc (ISO IO) instead of tell/1 etc (Edinburgh IO) is generally better; check false's post
predicate loop_through_list(List), always fails, so to succed you just have to write \+loop_through_list(List),

Resources