how to use retract boolean value in prolog? - 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".

Related

Prolog: Redirect system output

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.

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

use operator as constructor in prolog

I'm writing a function called leagalCourse, it takes just one parameter, a course list. A course like, for example, john+mary+94 would represent a project done by John and Mary with a mark of 94.
It should be true if the course data is “legal”, which means that it must not have a project with the same name twice such as john+john+70.
There also must not be two projects in the list containing the same pair of students. So if there’s a project harry+ron+82 in the list, it would be illegal for the list also to contain harry+ron+90 or ron+harry+63.
There is a sample output:
?- legalCourse([one+two+3,four+five+6,one+six+7]).
true.
?- legalCourse([one+two+3,four+four+6,one+six+7]).
false.
?- legalCourse([one+two+3,four+five+6,one+two+7]).
false.
?- legalCourse([one+two+3,two+one+6,one+six+7]).
false.
This is what I tried:
legalCourse([]).
legalCourse(X) :-
diffName(X).
legalCourse([Project|M]):-
diffName(Project),
not(samePair([Project|M])),
legalCourse(M).
diffName(Name1+Name2+_) :-
Name1 \= Name2.
/*can not have duplicated group*/
samePair([Name1+Name2+_|More]) :-
append([[head],tail,More]),
member(Name1,[head]),
member(Name2,[head]).
The function partially worked before I added the samePair predicate.
I think this works, you need to switch the vars and check both are different in check_no_dups/1.
legalCourse(List):-
maplist(triple_double,List,ListDouble),
check_no_dups(ListDouble).
check_no_dups([]).
check_no_dups([H|T]):-
H =X+Y,
maplist(dif(H),T),
H2 =Y+X,
maplist(dif(H2),T),
check_no_dups(T).
triple_double(X+Y+_Z,X+Y):-dif(X,Y).

Prolog - Ran into an issue

minu('-').
minu('+').
minu('/').
f(A):-
atom_chars(A,X),
write(X),
fun(X).
fun([]).
fun([A]):-
not(minu(A)).
fun([Hd|Tail]):-
not(minu(Hd)),
fun(Tail).
I am trying to make an function "f" that takes a string and returns True if "-", "+" or "/" are not in it.
But as soon as I use recursive call. It just returns false.
EDIT ::
SOLUTION FOUND ::
Thank you, lurker... And thank you, Daniel Lyons...
I apologize it has been a long day learning Prolog... I ought to go get some sleep.
f(A):-
atom_chars(A,X),
write(X),
fun(X).
fun([]).
fun([A]):-
not(minu(A)).
fun([Hd|Tail]):-
not(minu(Hd)),
fun(Tail).
I'd try this:
minu('-').
minu('+').
minu('/').
f(A) :-
atom_chars(A, Chars),
\+ (minu(Op), memberchk(Op, Chars)).
By the way, it's important to note that Prolog will not "return" anything; it will either tell you true or false if the goal succeeds or not, so for instance:
?- f("this is a string").
true.
?- f("this i-a string").
false.
?- f("this i+a string").
false.

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