Related
If I use the predicates member or the nt1 in SWI-Prolog as follows:
?- member(X, [A]).
X = A.
or
nth1(N, [A], X).
N = 1,
A = X.
The interpreter unifies the variable A as X.
Is their some alternative version of this functions which does not use the unification. Means, if I call something like this:
?- _member(X, [A]).
it would give
false
as long as the call is not
?- member(X, [X]).
which would lead to
true
And in the same way
_nth1(N, [A], X).
would give false
but
_nth1(N, [X], X).
would give
N = 1
Seems like you just need to roll your own using ==/2 instead of =/2:
See https://swish.swi-prolog.org/p/DqhYGuEf.pl
is_member_of( X , [Y|_] ) :- X == Y .
is_member_of( X , [_|Ys] ) :- is_member_of(X,Ys) .
is_nth0( N , L , E ) :- is_nth(0,L,E,N) .
is_nth1( N , L , E ) :- is_nth(1,L,E,N) .
is_nth( N , [Y|_] , X , N ) :- X == Y .
is_nth( I , [_|Ys] , X , N ) :- J is I+1, is_nth(J,Ys,X,N) .
First of all I am completely new to prolog and I am trying to write a predicate length(M,X,N) which is true, if M differs from N more than X.
I wrote the following testcase which is true if M(=dec.5) and N(=dec.2) differ more than X(=dec.2). And it is true in this case because 5 and 2 have a difference of 3 which is more than 2:
?- length(s(s(s(s(s(0))))), s(s(0)), s(s(0))).
true .
I know that prolog works recursively so I am wondering if I can construct such a predicate with conditions (for example <,>) like in languages like C, or if there is another way to do this in prolog. Sorry for this simple question but I just started with prolog.
You could construct predicates for greater or less. For example:
greater_than(s(_), 0).
greater_than(s(X), s(Y)) :-
greater_than(X, Y).
And similarly:
less_than(0, s(_)).
less_than(s(X), s(Y)) :-
less_than(X, Y).
If you want to find the absolute difference, you could do something like this:
abs_diff(0, 0, 0).
abs_diff(s(X), 0, s(X)).
abs_diff(0, s(X), s(X)).
abs_diff(s(X), s(Y), D) :-
abs_diff(X, Y, D).
Those concepts should help kick start some ideas for how to solve the rest of the problem.
This answer follows up on #lurker's fine answer and improves the determinism of the auxiliary predicate abs_diff/3 by utilizing
first argument clause indexing.
Introducing x_y_dist/3:
x_y_dist(0, Y, Y).
x_y_dist(s(X), Y, Z) :-
y_sx_dist(Y, X, Z).
y_sx_dist(0, X, s(X)).
y_sx_dist(s(Y), X, Z) :-
x_y_dist(X, Y, Z).
Sample query:
?- x_y_dist(X, Y, s(s(0))). % |X-Y| = 2
( X = 0 , Y = s(s(0)) % |0-2| = 2
; X = s(s(0)) , Y = 0 % |2-0| = 2
; X = s(0) , Y = s(s(s(0))) % |1-3| = 2
; X = s(s(s(0))) , Y = s(0) % |3-1| = 2
; X = s(s(0)) , Y = s(s(s(s(0)))) % |2-4| = 2
; X = s(s(s(s(0)))) , Y = s(s(0)) % |4-2| = 2
; X = s(s(s(0))) , Y = s(s(s(s(s(0))))) % |3-5| = 2
; X = s(s(s(s(s(0))))), Y = s(s(s(0))) % |5-3| = 2
; X = s(s(s(s(0)))) , Y = s(s(s(s(s(s(0)))))) % |4-6| = 2
; .........
)
Try this:
?- length(s(s(s(s(s(0))))), s(s(0)), s(s(0))).
length(s(_),0,0).
length(s(M),s(X),s(N)) :- length(M,X,N).
Do keep in mind that Prolog's predicates do not return values - so they don't return true or false. They either succeed or they don't. The interpreter is just telling you if your program succeeds or not.
This question already has answers here:
Dividing two integers with an alternative way
(3 answers)
Closed 7 years ago.
I have written the following code:
nat(0).
nat(s(X)) :- nat(X).
divide(0,_,0).
divide(X,Y,D) :- X#<Y, D is 0.
divide(X,s(0),X).
divide(_,0,undefined) :- !.
Everything is right up to here. but what should i write, to calculate the division of two other naturals? for example
divide(s(s(s(s(s(s(s(s(0)))))))),s(s(0)),D).???
I think the easiest way would be to define subtraction and then apply it recursively with a counter. I'm not able to run this right now but I assume it'd look something like this:
nat(0).
nat(s(X)) :- nat(X).
divide(_,0,_):- !, fail.
divide(X,Y,R):-
iter_subtract(X,Y,0,R).
iter_subtract(X,Y,N,N):- X#<Y, !.
iter_subtract(X,Y,C,R):-
subtract(X,Y,N),
D = s(C),
iter_subtract(N,Y,D,R).
subtract(A,0,A):-!.
subtract(s(X),s(B),R):-
subtract(X,B,R).
you can easily divide two numbers as following:
mydiv(0,_,0).
mydiv(_,0,undefined):- !.
mydiv(X,Y,D) :- X >= Y , Z is X - Y , mydiv(Z,Y,M) , D is M + 1 .
output:
?- mydiv(10,4,Q). false.
?- mydiv(100,2,Q). Q = 50 .
to run with debug info:
mydiv(0,_,0) :- write('mydiv(0,_,0)\n').
mydiv(_,0,undefined):- write('mydiv(_,0,undefined)\n'),!.
mydiv(X,Y,D) :- write('mydiv('),write(X) , write(','), write(Y) , write(',') , write(D) , write(')') , nl,
X >= Y , Z is X - Y , mydiv(Z,Y,M) , D is M + 1 .
output:
?- mydiv(20,2,Q). mydiv(20,2,_G3941) mydiv(18,2,_L1420)
mydiv(16,2,_L1435) mydiv(14,2,_L1450) mydiv(12,2,_L1465)
mydiv(10,2,_L1480) mydiv(8,2,_L1495) mydiv(6,2,_L1510)
mydiv(4,2,_L1525) mydiv(2,2,_L1540) mydiv(0,__,0) Q = 10 .
with natural function:
natural(0).
natural(X) :- X < 0 , !, fail.
natural(X) :- Y is X - 1 , natural(Y).
mydiv(0,_,0) :- write('mydiv(0,_,0)\n').
mydiv(_,0,undefined):- write('mydiv(_,0,undefined)\n'),!.
mydiv(X,Y,D) :- write('mydiv('),write(X) , write(','), write(Y) , write(',') , write(D) , write(')') , nl,
natural(X), natural(Y), X >= Y , Z is X - Y , mydiv(Z,Y,M) , D is M + 1 .
How to write a predicate minmax(L, X, Y) to find out min value of X and max value of Y in list of integer L.
Example:
?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10, Y = 7.
Let's define list_minnum_maxnum/3 like list_minnum/2:
list_minnum_maxnum([E|Es],Min,Max) :-
V is E,
list_minnum0_minnum_maxnum0_maxnum(Es,V,Min,V,Max).
list_minnum0_minnum_maxnum0_maxnum([] ,Min ,Min,Max ,Max).
list_minnum0_minnum_maxnum0_maxnum([E|Es],Min0,Min,Max0,Max) :-
V is E,
Min1 is min(Min0,V),
Max1 is max(Max0,V),
list_minnum0_minnum_maxnum0_maxnum(Es,Min1,Min,Max1,Max).
Sample query as given by the OP:
?- list_minnum_maxnum([1,-10,1,0,7,7], Min,Max).
Min = -10,
Max = 7.
Note that this implementation of list_minnum_maxnum/3 works with all kinds of numbers.
?- list_minnum_maxnum([1,-10,1,0,7.2,7,7], Min,Max).
Min = -10,
Max = 7.2.
If you only care about handling integers, use clpfd!
:- use_module(library(clpfd)).
We define list_zmin_zmax/3 as follows:
list_zmin_zmax([E|Es],Min,Max) :-
V #= E,
list_zmin0_zmin_zmax0_zmax(Es,V,Min,V,Max).
list_zmin0_zmin_zmax0_zmax([] ,Min ,Min,Max ,Max).
list_zmin0_zmin_zmax0_zmax([E|Es],Min0,Min,Max0,Max) :-
V #= E,
Min1 #= min(Min0,V),
Max1 #= max(Max0,V),
list_zmin0_zmin_zmax0_zmax(Es,Min1,Min,Max1,Max).
Same sample use as before:
?- list_zmin_zmax([1,-10,1,0,7,7], Min,Max).
Min = -10,
Max = 7.
OK! What about support for non-integer numbers?
?- list_zmin_zmax([1,-10,1,0,7.2,7,7], Min,Max).
ERROR: Domain error: `clpfd_expression' expected, found `7.2'
We expected getting an error, we got an error...
Note that thanks to clpfd, we can run more general queries, too!
?- list_zmin_zmax([A,B], Min,Max).
A #>= Min, Max #>= A, Min #= min(A,B),
B #>= Min, Max #>= B, Max #= max(A,B).
As noted, you need to iterate over the list, accumulating the min and max values as you go. So, assuming that you have to write this from scratch, the first thing you need to do is decompose the problem into simple steps:
You need a means of comparing two objects and determine which is the lower or higher.
You need a means of iterating over the loop and tracking the min and max values seen as you go.
That leads to a min/3 and max/3, thus:
min(X,X,X).
min(X,Y,X) :- X < Y .
min(X,Y,Y) :- X > Y .
max(X,X,X).
max(X,Y,X) :- X > Y .
max(X,Y,Y) :- X < Y .
For your purposes here, one could even combine them into a single predicate, if you liked:
rank( X , X , X , X ) .
rank( X , Y , X , Y ) :- X < Y .
rank( X , Y , Y , X ) :- X > Y .
A pretty typical programming pattern in Prolog is to have a simple public API predicate that invokes a private "worker" predicate that does the actual work. Often the worker predicate will carry temporary "accumulator" variables that simplify the job. Your public predicate might look like:
minmax([X|Xs],Min,Max) :- minmax_scan( Xs , X , X , Min , Max ).
Here, your public API predicate accepts a non-empty list, seeding the min/max accumulators the worker predicate uses with the head of the list, then calling the worker predicate with the tail of the list.
Your worker predicate then might look like this:
% if the list is empty, we've solved the puzzle, right?
minmax_scan( [] , Min , Max , Min , Max ) .
% if the list is non-empty, we need to compare its head to
% the current value for min/max to determine the new values for min/max
% (which might be the same), and then recurse down on the tail of the list
minmax_scan( [X|Xs] , CurrMin , CurrMax , Min , Max ) :-
min( X , CurrMin , NextMin ) ,
max( X , CurrMax , NextMax ) ,
minmax_scan( Xs , NextMin , NextMax , Min , Max )
.
Easy!
Here's something convoluted and a bit complex.
is_minmax(A,B-D,C-E) :-
D is min(...),
E is max(...) .
pair(A,B,A-B).
minmax(L,MIN,MAX) :-
L=[A|_], length(L,N), N2 is N-1,
length(L2,N2), append(L2,[MIN],L22),
length(L3,N2), append(L3,[MAX],L33),
maplist(pair, [A|L2], L22, KL2),
maplist(pair, [A|L3], L33, KL3),
maplist(is_minmax, L, KL2, KL3).
(works in SWI Prolog). Try to figure out what to write in place of dots ....
take the first value from the list, then examine each other element of the list, selecting lower/higher values as temporary min/max.
When at the end of list, you have both...
minmax([First|Rest], Min, Max) :-
minmax(Rest, First, First, Min, Max).
minmax([], Min, Max, Min, Max).
minmax([Value|Ns], MinCurr, MaxCurr, Min, Max) :-
....
minmax(Ns, MinNext, MaxNext, Min, Max).
I'll let you write the tests before the recursive call (i.e. fill the dots!)
edit just to point out library(aggregate), available in several Prolog systems:
1 ?- [user].
minmax(L, X, Y) :- aggregate( (min(E), max(E)), member(E, L), (X, Y) ).
|:
true.
2 ?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10,
Y = 7.
I am to write a program that does this:
?- pLeap(2,5,X,Y).
X = 2,
Y = 3 ;
X = 3,
Y = 4 ;
X = 4,
Y = 5 ;
X = 5,
Y = 5 ;
false.
(gives all pairs X,X+1 between 2 and 5, plus the special case at the end).
This is supposedly the solution. I don't really understand how it works, could anyone guide me through it?
pLeap(X,X,X,X).
pLeap(L,H,X,Y) :-
L<H,
X is L,
Y is X+1.
pLeap(L,H,X,Y) :-
L=<H,
L1 is L+1,
pLeap(L1,H,X,Y).
I'd do it simply like this:
pLeap(L,H,X,Y) :-
X >= L,
X =< H,
Y is X+1.
Why doesn't it work (ignoring the special case at the end)?
You could use library clpfd for you problem.
:- use_module(library(clpfd)).
pLeap(L,H,X,Y) :-
X in L..H,
Y #= min(H, X+1),
label([X]).
Here is the output:
?- pLeap(2,5,X,Y).
X = 2,
Y = 3 ;
X = 3,
Y = 4 ;
X = 4,
Y = 5 ;
X = 5,
Y = 5.
The >= and =< operators don't instantiate their arguments, and you can only use them once the arguments have already been instantiated.
Put another way, in the given solution, X and Y are given values with is, and the < and =< operators are only used on L and H, whose values are given by the user. (On the given solution, try pLeap(L,H,2,3) and you'll get the same problem as you're having.)
In your case, though, you try to use >= and =< on X, which has no value yet, and so the interpreter complains.