Prolog: Redirect system output - prolog

There are Prolog predicates that output error messages, like load_files/1 in case the file could not be found:
error(existence_error(source_sink,'/home/foo/nothinghere.txt'),_3724).
These error messages are just printed to stdout but are not returned as prolog return value.
In my case, load_files/1 gets called deep down as part of a procedure that I don't want to modify. I just deliver the file name and wait for the return value. But as far as I understand, the return value, in this case, is either True or an error. Is there any way for me to redirect the error output to the return value so that I can actually do something with the output I am getting?

You could use catch/3.
?- catch(load_files('/tmp/exists.prolog'), E, true).
true.
?- catch(load_files('/tmp/notexists.prolog'), E, true).
E = error(existence_error(source_sink, '/tmp/notexists.prolog'), _).
catch(:Goal, +Catcher, :Recover) is used for catching throw(_) from the :Goal.
Catcher is unified with the argument of throw/1.
Recover is called using call/1.
In the above example E unifies with any error. We do not want that, so we can do something like:
catchFileErrors(G, F) :-
catch(G, error(existence_error(source_sink, F), _), true).
?- catchFileErrors(load_files('exists.prolog'), E).
true.
?- catchFileErrors(load_files('notexists.prolog'), E).
E = 'notexists.prolog'.
You can pass a goal as the last argument to catch if you have a strategy to recover from the error.

Related

When the prolog returns sat as an output what does it mean?

When I run my code it returns the sat as the output ? Is it trying to convey an error or what does the output means ?
%Scenario 2:
%Amy: “My report is original.”
%Brian: “Mine as well”
report(2, [Amy,Brian]) :-
sat(Amy=:=Amy),
sat(Brian=:=Brian),
write('1 they are telling the truth , 0 they are lying').
The output that I get is :-
It is not trying to convey you an error, it is being as specific as it can be. That is sat(Amy=:=Amy), sat(Brian=:=Brian) is satisfiable whenever sat(Amy=:=Amy) and sat(Brian=:=Brian).
CLP(B) does not automatically designate variables in expressions to be boolean. You can use labeling(+Vs) to inform it as follows:
?- use_module(library(clpb)).
?- sat(Amy=:=Amy), sat(Brian=:=Brian), labeling([X,Y]).
X = Y, Y = 0,
sat(Amy=:=Amy),
sat(Brian=:=Brian)
This is only the first solution you can use backtrack to obtain the others.

Prolog, can't figure out how to get final value from function at base case

I'm not sure how to solve this error. placePoly works correctly and is eventually called with the result I desire in the last argument, but when I trace it in SWI Prolog it just backtracks to the beginning and doesn't return anything. Shouldn't it return once it hits the base case?
placePoly([],_,_,_) :- !.
placePoly([(X,Y)|T],Letter,Board,_) :- setPixel(X,Y,Letter,Board,NewBoard),
placePoly(T,Letter,NewBoard,NewBoard).
setPixel(X,Y,Letter,P,NewP) :- getElement(Y,P,Row),
setElement(Y,NewRow,P,NewP),
setElement(X,Letter,Row,NewRow).

how to use retract boolean value in prolog?

Is it possible to use retract's returning value?
I just want to make function to print out words, instead of boolean value,
so I try to compare the retract value to print the statement but it seems not working.
The predicate retract/1 can succeed or fail, just like any other predicate.
:- assert(a).
test :-
retract(a),
writeln('a used to be true, but not any more.'), !.
test :-
writeln('a was false').
In the example above, when evaluating test., retract(a) succeeds, so the writeln('...') is evaluated, which always succeeds.
After that, a cut, so we can't backtrack to the second clause.
%:- assert(a).
test :-
retract(a),
writeln('a used to be true, but not any more.'), !.
test :-
writeln('a was false').
In this example, with the assert(a) being commented out, retract(a) fails, so we get to the second clause of test/0, which succeeds by writing "a was false".

error handling in gprolog?

In order to run a group of queries in a simple query, I have tagged these queries and use forall/2 to call them:
query_all :-
forall(query(Q), (Q ->
format('yes: ~w~n',[Q]) ;
format('no : ~w~n',[Q]))).
so if I define something like query(true)., I'll be able to see yes: true from the output.
The problem here is that query( ... ) do not always exist, when prolog can't find anything that tagged query, forall/2 will fail and cause exception saying "error(existence_error(procedure,query/1),forall/2)"
I want to handle this exception, but not to break the whole control flow.
I know catch/3 would help me but I don't know how to use it, my code is:
catch(query_all, error(existence_error(procedure,_),_), recovery).
recovery :-
format('error occurred.~n',[]).
but prolog says "native code procedure catch/3 cannot be redefined".
Is there something I've missed?
You can either declare query/1 as dynamic in your code adding this line:
:-dynamic(query/1).
or use catch/3 as you suggested, however you don't have to redefine it but use it instead, e.g:
query_all :-
catch(
forall(query(Q), (Q ->
format('yes: ~w~n',[Q]) ;
format('no : ~w~n',[Q]))),
error(existence_error(procedure, _), _), format('error occurred.~n', [])).

Prolog, how to show multiple output in write()

go :- match(Mn,Fn),
write('--Matching Result--'),
nl,
write(Mn),
write(' match with '),
write(Fn),
match(Mn1,Fn1).
person(may,female,25,blue).
person(rose,female,20,blue).
person(hock,male,30,blue).
person(ali,male,24,blue).
match(Mn,Fn):-person(Fn,'female',Fage,Fatt),
person(Mn,'male',Mage,Matt),
Mage>=Fage,
Fatt=Matt.
Hi,this is my code...but it's only can show the 1 output...but there are 3 pair of matching in match(X,Y).how to show them all in my go function.
Thank you
You get all your matches if you force backtracking, usually by entering ; (e.g. in SWI Prolog). But you also see that you are getting unnecessary outputs true. This is because the last clause in go is match(Mn1,Fn1). This clause succeeds three times and binds the variables Mn1,Fn1 but then only true is output, because you do not write() after that clause. The fourth time match(Mn1,Fn1) fails and by backtracking you come back to the first clause match(Mn,Fn) that matches, the match is output, etc.
You surely do not want to have this behavior. You should remove the last clause match(Mn1,Fn1) in go. Now by pressing ; you get the 3 matches without any output true in between.
But what you likely want is that the program does the backtracking. To achieve this, you just need to force backtracking by adding false as the last clause. To get proper formatting of the output, use the following program. The last clause go2. is added to get true at the very end.
go2 :- write('--Matching Result--'), nl,
match(Mn,Fn),
write(Mn), write(' match with '), write(Fn), nl,
fail.
go2.
This technique is called failure driven loop.
If you have any predicate that has multiple results and want to to find all of them, you should use findall/3
For example, in your case, you could do something like:
findall([X,Y], match(X,Y),L).
L will be a list that will contain all the X,Y that satisfy match(X,Y) in the format [X,Y].
for example, assuming that:
match(m1,f1).
match(m2,f2).
the result will be L = [ [m1,f1], [m2,f2] ]
note that you can define the format as you wish, for example you could write:
findall(pair(X,Y), match(X,Y), L).
L = [ pair(m1,f1), pair(m2,f2) ]
findall( X, match(X,Y), L).
L = [ m1, m2]
findall( 42, match(X,Y), L).
L = [42, 42]
then you have to recurse on the list to print them.
However, if you wish to find one result, run some code and then continue you could use forall/2:
forall(match(X,Y), my_print(X,Y).
Prolog is a lazy language. Which means that it will stop once it has found a condition that made your problem true. This will be the very first match alone.
IF your code is working (I haven't tried it), then you should try and run the match-statement like this in your prolog inspector: match(X,Y)
The prolog inspector will return all states and print them for you.

Resources