Janek Podwysocki
Janek Podwysocki

Reputation: 593

Why Do i receive "Singleton variable" warning and incorrect result?

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

Answers (2)

David Tonhofer
David Tonhofer

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

Reema Q Khan
Reema Q Khan

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

Related Questions