prolog, taking only first answer - prolog

I've read some topics on this subjects, but I can't get it to work. Assume I have following predicate:
wins(L,K,X):-member(X,L),X>=K.
wins(L,K,X):-member(X,L),X<K,K1 is K-X,\+wins(L,K1,_).
It doesn't really matter what it does, the thing is that for example:
?- wins([1,4],1,X).
X = 1;
X = 4;
false.
Now, this predicate helps me to check to find if some condition can be fulfilled and gives the numbers that allow to achieve this. That's OK, but now I would only like to get the first asnwer, which is X = 1 here and then make Prolog stop searching. Yet, I can't use !, becuase then it finds the X = 1 and return false. And I need it to return true, in case I have other following conditions based on resulting X, like:
play(L,K,X):- member(X,L),K1 is K-X,K1>0,wins(L,K1,Y),K2 is K1-Y, ...
Then in ... I want to be able to use only the first one result from win predicate. I need to use SWI-Prolog.
Thanks!
EDIT
Maybe I should expand it more, because once() is working, but not exactly as I would like to. I mean if I wanted to wait for the user input, let's say:
play(L,K,X):-
member(X, L),
K1 is K-X,
K1 > 0,
once(wins(L, K1, Y)),
K2 is K1 - Y,
write('Something: '),
read(Z),
...
In that case on the output I would get:
Something: |:
After I press any portion of text (to read Z), let's say 'THIS', it goes like:
SomethingTHIS.
What I mean is that some part of the previous text put into output disappears (in this case it's ': ' that's missing).
Any idead how I could fix this?

Related

Prolog : return variable, check if variable is of certain type?

I am new to Prolog and can't understand predicates very well.
First question: How can I 'return' a certain variable?
We have alternate(?A, ?B). alternate(first, second) should give me back second, and alternate(second, first) should give back first.
Second question: How to check if variable is of certain type?
I have for example ispair(?Pair). I have to check if Pair is pos(X,Y).
Not sure if that's what you meant, but what about the following:
alternate(first, pair(X,_), X).
alternate(second, pair(_,X), X).
If you query without any restrictions, you get the following two answer substitutions:
?- alternate(X,Y,Z).
X = first,
Y = pair(Z, _5844) ; % hit ; to get the second answer
X = second,
Y = pair(_5842, Z). % variables _12345 are fresh ones created by prolog
You can also ask: on which side of the pair (a,b) is b?
?- alternate(Where, pair(a,b), b).
Where = second.
In the case that your pair is (b,b), you get two solutions:
?- alternate(Where, pair(b,b), b).
Where = first ;
Where = second.
Also, c is not part of the pair (a,b):
?- alternate(Where, pair(a,b), c).
false.
If you insist on picking an element from heaven, you will get no as answer:
?- alternate(heaven, X, Y).
false.
When you know that the first element of a pair is a, prolog will tell you how the pair must look like:
?- alternate(first, X, a).
X = pair(a, _5680).
Again we have a fresh variable (_5680) in there, because any second term is fine.

Prolog return a list which contains only elements which are equal to head of the list

Hello I would like to ask a doubt I have with the following code:
principio([],[]).
principio([H],[H]).
principio([H,_|_],[H]).
principio([H,H|C],P) :-
principio([H|C],R),P=[H|R].
I would like a way to get from:
?- principio([222,333,101,202,12,222,13,222],X).
X = [222,222,222]
But in this moment I get just the head:
X = [222]
So, to keep it clear I'd like: all successive occurrences of the first element as a list.
My doubt is what does this assignment P=[H|R] why not to put just:
principio([H,H|C],P) :-
principio([H|C],P)
Also, how would you try to modify this to get the result I asked for?
Thank you
Here is two ways how you can narrow down the problem. 1st, start from an unexpectedly failing query. 2nd, start from a query that should fail but rather succeeds.
1st Diagnose unexpected incompleteness
Determine a most specific failing query
?- principio([222,333,101,202,12,222,13,222],[222,222,222]).
false.
Generalize the query
... as much as possible. I could do this manually, or I could let Prolog do the work for me. Here I use library(diadem):
?- use_module(diadem).
true.
?- principio([222,333,101,202,12,222,13,222],[222,222,222]).? Gen.
Gen = principio([222, 333|_], [_, _|_])
; Gen = (dif(A100, B100), principio([A100, B100|_], [_, _|_]))
; ... .
In other words: Not only does your original query fail, but also this generalization fails! Here, we only insist that the first two elements are different, and that the resulting list contains at least two elements — no matter which!
?- dif(X, Y), principio([X,Y|_],[_,_|_]).
Generalize your program
:- op(950, fy, *).
* _P_0.
principio([], _/*[]*/).
principio([_H], _/*[H]*/).
principio([H,_|_],[H]).
principio([H,H|C],P) :-
* principio([H|C],R),
* P=[H|R].
The error must reside in the little remaining part of your program. No need to read any further!
The problem is that for a list starting with two different elements you only have the clause principio([H,_|_],[H]).. So this part has to be generalized somehow.
2nd Diagnose unexpected unsoundness
Another way of finding the error would be to start with the unexpected solution:
?- principio([222,333,101,202,12,222,13,222],[222]).
true. % incorrect !!
And then reduce the size of the query as much as possible.
?- principio([222,222],[222]).
true. % incorrect !!
Now, specialize your program inserting false as long as above query succeeds:
principio([],[]) : - false.
principio([H],[H]) :- false.
principio([H,_|_],[H]).
principio([H,H|C],P) :- false,
principio([H|C],R),
P=[H|R].
The remaining visible part is the culprit! We have to revise it. What it says is:
Any list starting with two elements corresponds to the list with the first element only.
principio([],[]).
principio([H],[H]).
principio([H,D|Xs], [H|Hs]) :-
dif(H,D),
principio([H|Xs],[H|Hs]).
principio([H,H|Xs],[H|Hs]) :-
principio([H|Xs],Hs).
In addition to the very nice answer provided by #false (+s(0)), I would point out the possibility to use DCGs for the task. They usually yield easily readable code when describing lists (see comments beside the grammar rules):
principio([H|T],Hs) :-
phrase(heads([H|T],H),Hs).
heads([],_H) --> % in the empty list
[]. % there's no element matching H
heads([H|Xs],H) --> % if the head of the list matches H
[H], % it's in the list
heads(Xs,H). % same for the tail
heads([X|Xs],H) --> % if the head of the list is
{dif(X,H)}, % different from H it's not in the list
heads(Xs,H). % same for the tail
Thus your example query yields the desired result:
?- principio([222,333,101,202,12,222,13,222],X).
X = [222,222,222] ? ;
no

Prolog - Domain error: 'acyclic_term ' expected

What I have to do is, write a predicate Multiplication/3, whose first argument is an integer, second argument is a list, and the third argument is the result of multiplying the integer with the list, for example:
?-Multiplication(3,[2,7,4],Result).
should return
Result = [6,21,12].
Here's my code:
Multiplication(X,[],Result).
Multiplication(X,[Head|Tail],Result) :-
Y is X*Head,
append([Result], [Y], L),
append([],L,Result), // HERE
Multiplication(X,Tail,Result).
And I get the following error:
Domain error: 'acyclic_term ' expected, found '#(lists:append([],S_1,S_1),[S_1=[S_1,1]])'
on the second append call.
If anyone knows why I receive the error, how to fix it or another way to solve this, I'm open to ideas.
Your two goals append([Result], [Y], L), append([],L,Result) are exactly the same as:
L = [Result,Y], L = Result.
or even simpler:
L = [L,Y]
which would result either in silent failure or an infinite term. Instead, your Prolog produces an error, so that you can correct your program.
In your original code:
Multiplication(X,[Head|Tail],Result) :-
Y is X*Head,
append([Result], [Y], L),
append([],L,Result), // HERE
Multiplication(X,Tail,Result).
You're getting a "cycle" because you're appending Result to something to get L, then appending something to L to get Result. That's not good. You also have a capitalized predicate name, which is a syntax error. (I assume that, since you ran your code, it wasn't capitalized in the original version.)
You're new proposed solution is overly complicated. Why do you need the 4th argument? Also, your base case for return (which is return(X, [], Result) doesn't make sense, as it has to singleton variables. The use of append/3 is overkill since recursion handles the iteration through the list elements for you.
Starting from the top, you have a common pattern in Prolog where you want to run a query on corresponding elements of two or more lists. A simple recursive solution would look something like this:
multiplication(_, [], []). % Multiplying anything by the empty list is the empty list
multiplication(M, [X|Xs], [XX|XXs]) :-
XX is M * X,
multiplication(M, Xs, XXs).
Another way to implement this kind of pattern in Prolog is with maplist/3. You can first define the query on corresponding elements:
multiply(X, Y, Product) :- Product is X * Y.
Then use maplist/3:
multiplication(M, List, Result) :-
maplist(multiply(M), List, Result).
Maplist will do a call(multiply(M), ...) on each corresponding pair of elements of List and Result.
I edited the code and came up with this:
multiplication(X,[],Result,Result).
multiplication(X,[Head|Tail],List,Result) :-
Y is X*Head,
append(List, [Y], L),
multiplication(X,Tail,L,Result).
return(X,[],Result).
return(X,L,Result) :-
multiplication(X,L,_,Result).
and the query:
return(2,[1,2],Result).
After the first run, it seems to return Result as it should be, but it runs forever.

how to solve when the number of variables in the goal/query varies - Prolog Constrain Solver

Here's a snippet on the classic SENDMORY crypt-arithmetic problem solutiong using prolog constraint solving mechanism-
:- lib(ic).
sendmore(Digits) :-
Digits = [S,E,N,D,M,O,R,Y],
Digits :: [0..9],
alldifferent(Digits),
S #\= 0,
M #\= 0,
1000*S + 100*E + 10*N + D
+ 1000*M + 100*O + 10*R + E
#= 10000*M + 1000*O + 100*N + 10*E + Y,
labeling(Digits).
Now, to execute this, I would send a goal/query like this:
?- sendmore(Digits).
And that would return me the possible solutions for the digits.
Now, my question is, I do not want to sort of "hard-code" the variables (like S,E,N,...) this way, but the goal/query would give the number of variables. For example, if the query I pass is something like:
?- sendmore(S,E,N,D,M).
then, it should compute only the values of SENDM and assume that the other variables are not applicable, and hence assign 0 to those variables and then proceed with the computation. And the next time I query, I may pass a different number of variables in the query.. like example:
?- sendmore(S,N,D,M,O,Y).
and the program should compute likewise.
What I am trying to achieve is a more generalised problem solver for the above scenario. Any directions on this is really appreciated. I am quite new to prolog,and am using ECLIPSE constraint solver.
Thank You.
Here are 2 ideas:
You can define sendmore() with different numbers of parameters, which would call the "real" version with the missing ones filled in. But you couldn't have different versions with the same NUMBER of parameters but DIFFERENT ones (since Prolog matches args to parameters by position).
You could expand/complicate your list format to allow the specification of which parameters you are passing; something line [(s,S),(e,E),(n,N),(d,D),(m,M)] for your middle example. A little tedious, but gives you the flexibility you seem to want.
Normally, variables in a goal and variables in a clause head are matched by their positions, not their names. So a call ?- sendmore0([S,E,N,D,M]). should be implemented as:
sendmore0([S,E,N,D,M]) :- sendmore([S,E,N,D,M,_,_,_]).
However, this would mean that you would need to implement this for every possible combination.
If you really want to implement what you describe, then you need to give the variable stable names. In ECLiPSe, you can do this with the library var_name. It's quite a hack, though...
:- lib(var_name).
sendmore0(L) :-
build_arg(["S","E","N","D","M',"O","R","Y"], L, A),
sendmore(A).
build_arg([], _, []) :- !.
build_arg([H|T], L, [HA|HT]) :-
match_arg(L, H, HA),
build_arg(T, L, HT).
match_arg([], _, _). % or use 0 as last argument if you want
match_arg([H|T], Base, A) :-
(
get_var_name(H, S),
split_string(S,"#","",[Base,_])
->
A = H
;
match_arg(T, Base, A)
).
Then you can call sendmore0/1 with a shorter list of variables. Don't forget to set the variable names!
?- set_var_name(S, "S"), set_var_name(E, "E"), sendmore0([S, E]).
S = 9
E = 5
Yes (0.00s cpu, solution 1, maybe more)
Disclaimer: this is not what stable names are for. They are meant for debugging purposes. If Joachim ever sees this, he'll give me a sharp clip round the ears...

Use cut in Prolog to define a once_member/2 function

Disclaimer: This is informal and non-assessed coursework to do in my own time. I have tried it myself, failed and am now looking for some guidance.
I am trying to implement a version of the member/2 function which will only return members for a list once.
For example:
| ?- member(X, [1,2,3,1]).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
X = 1 ? ;
I would like it to only print out each number a maximum of once.
| ?- once_member(X, [1,2,3,1]).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
no
We have been told to do this with the cut '!' operator but I have looked over the notes for my course for cut and more online and yet still can't make it click in my head!
So far I have managed to get:
once_member(E, [E | L]) :- !.
once_member(E, [_, L]) :-
once_member(E, L).
Which returns 1 and then nothing else, I feel like my cut is in the wrong place and preventing a backtrack for each possible match but I'm really not sure where to go with it next.
I have looked in my course notes and also at: http://www.cs.ubbcluj.ro/~csatol/log_funk/prolog/slides/5-cuts.pdf and Programming in Prolog (Google Books)
Guidance on how to logically apply the cut would be most useful, but the answer might help me figure that out myself.
We have also been told to do another method which uses '\+' negation by failure but hopefully this may be simpler once cut has twigged for me?
Remove redundant answers and stay pure!
We define memberd/2 based on if_/3 and (=)/3:
memberd(X, [E|Es]) :-
if_(X = E, true, memberd(X, Es)).
Particularly with meta-predicates, a different argument order may come in handy sometimes:
list_memberd(Es, X) :-
memberd(X, Es).
Sample query:
?- memberd(X, [1,2,3,1]).
X = 1 ;
X = 2 ;
X = 3 ;
false.
The solution with cut... at first it sounds quite troublesome.
Assuming that the first argument will be instantiated, a solution is trivial:
once_member(X,L):-
member(X,L),!.
but this will not have the behavior you want if the first arg is not instantiated.
If we know the domain of the lists elements (for example numbers between 1 and 42) we could instantiate the first argument:
once_member(X,L):-
between(1,42,X),
member_(X,L).
member_(X,L):-
member(X,L),!.
but this is veeery inefficient
at this point, I started to believe that it's not possible to do with just a cut (assuming that we dont use + or list_to_set/2
oh wait! < insert idea emoticon here >
If we could implement a predicate (like list_to_set/2 of swi-prolog) that would take a list and produce a list in which all the duplicate elements are removed we could simply use the normal member/2 and don't get duplicate results. Give it a try, I think that you will be able to write it yourself.
--------Spoilers------------
one_member(X,L):-
list_to_set(L,S),
member(X,S).
list_to_set([],[]).
list_to_set([H|T],[H|S]):-
remove_all(H,T,TT),
list_to_set(TT,S).
%remove_all(X,L,S): S is L if we remove all instances of X
remove_all(_,[],[]).
remove_all(X,[X|T],TT):-
remove_all(X,T,TT),!.
remove_all(X,[H|T],[H|TT]):-
remove_all(X,T,TT).
As you see we have to use a cut in remove_all/3 because otherwise the third clause can be matched by remove_all(X,[X|_],_) since we do not specify that H is different from X. I believe that the solution with not is trivial.
Btw, the solution with not could be characterized as more declarative than the solution with cut; the cut we used is typically called a red cut since it alters the behavior of the program. And there are other problems; note that, even with the cut, remove_all(1,[1,2],[1,2]) would succeed.
On the other hand it's not efficient to check twice for a condition. Therefore, the optimal would be to use the if-then-else structure (but I assume that you are not allowed to use it either; its implementation can be done with a cut).
On the other hand, there is another, easier implementation with not: you should not only check if X is member of the list but also if you have encountered it previously; so you will need an accumulator:
-------------Spoilers--------------------
once_member(X,L):-
once_member(X,L,[]).
once_member(X,[X|_T],A):-
\+once_member(X,A).
once_member(X,[H|T],A):-
once_member(X,T,[H|A]).
once_member(X, Xs) :-
sort(Xs, Ys),
member(X, Ys).
Like almost all other solutions posted, this has some anomalies.
?- X = 1, once_member(X, [A,B]).
X = A, A = 1
; X = B, B = 1.
?- X = 1, once_member(X, [A,A]).
X = A, A = 1.
Here's an approach that uses a cut in the definition of once_member/2 together with the classic member/2 predicate:
once_member(X,[H|T]) :-
member(H,T),
!,
once_member(X,T).
once_member(H,[H|_]).
once_member(X,[_|T]) :-
once_member(X,T).
Applied to the example above:
?- once_member(X,[1,2,3,1]).
X = 2 ;
X = 3 ;
X = 1 ;
no
Note: Despite the odd-appearing three clause definition, once_member/2 is last-call/tail-recursive optimization eligible due to the placement of the cut ahead of its first self-invocation.

Resources