Reputation: 593
i'm writing a simple function in prolog (beginer). Function calculates a specific type of quadratic equation (but this is not important, calculations are correct).
liniowa(A, B, R, W) :-
Delta is 4*A*A*R - 4*B*B + 4*R,
( Delta < 0
-> false
; ( Delta == 0
-> X is -B/(2*A),
Y is A*X + B,
W = punkt(X, Y)
; X1 is (-B + sqrt(Delta)) / (2*A),
Y1 is A*X1 + B,
X2 is (-B - sqrt(Delta)) / (2*A),
Y2 is A*X2 + B,
writeln(X1), writeln(Y1), writeln(X2), writeln(Y2),
W = punkt(X1, Y1) ; W = punkt(X2, Y2)
)
).
When i run this function, i receive warnings:
Singleton variable in branch: X2
Singleton variable in branch: Y2
In the result i receive strange things. In writeln(X2), writeln(Y2) everything is ok, but then there is sth strange in punkt(X2, Y2):
1.4142135623730951
1.4142135623730951
-1.4142135623730951
-1.4142135623730951
W = punkt(1.4142135623730951, 1.4142135623730951)
W = punkt(_1344, _1346)
What's happening? How should I make it?
Upvotes: 1
Views: 142
Reputation: 15328
The syntax of ->/2
is horrendous at the best of times. That no official better syntax has been developed in 30 years is a sad statement, but of what? I won't say anything more about this.
It is best to separate out the program parts into separate predicates.
(A further refinement could be to separate out the case "Delta == 0" into a dedicated delta_positive(A,B,W)
, thus avoiding having to make a decision on delta_positive/4
and thus cutting and guarding.
liniowa(A, B, R, W) :-
Delta is 4*A*A*R - 4*B*B + 4*R,
( Delta < 0 -> false ; delta_positive(Delta,A,B,W) ).
delta_positive(0,A,B,W) :-
!, % commit to this clause
X is -B/(2*A),
Y is A*X + B,
W = punkt(X,Y).
delta_positive(Delta,A,B,W) :-
Delta \== 0, % superfluous, but makes things clear
!, % commit is also superfluous
X1 is (-B + sqrt(Delta)) / (2*A),
Y1 is A*X1 + B,
X2 is (-B - sqrt(Delta)) / (2*A),
Y2 is A*X2 + B,
format("X1=~q, Y1=~q, Y2=~q, Y2=~q\n",[X1,Y1,X2,Y2]),
(W = punkt(X1, Y1) ; W = punkt(X2, Y2)).
This immediately shows that parantheses are missing around the expression:
(W = punkt(X1, Y1) ; W = punkt(X2, Y2))
.
Upvotes: 4
Reputation: 878
I tried solving it:-
liniowa(A, B, R, W) :-
Delta is 4*A*A*R - 4*B*B + 4*R,
( Delta < 0
-> false
; ( Delta == 0
-> X is -B/(2*A),
Y is A*X + B,
W = punkt(X, Y)
; X1 is (-B + sqrt(Delta)) / (2*A),
Y1 is A*X1 + B,
X2 is (-B - sqrt(Delta)) / (2*A),
Y2 is A*X2 + B,
writeln(X1), writeln(Y1), writeln(X2), writeln(Y2),
W = punkt(X1, Y1) ); X2 is (-B - sqrt(Delta)) / (2*A),
Y2 is A*X2 + B, W = punkt(X2, Y2)
).
?-liniowa(2, 3, 4, W).
0.9083123951776999
4.8166247903554
-2.4083123951777
-1.8166247903553998
W = punkt(0.9083123951776999, 4.8166247903554)
W = punkt(-2.4083123951777, -1.8166247903553998)
I believe that in your code the calculation is being done in the previous step, that's why it is unable to pick it in the last case.
Upvotes: 0