Prolog removing IF THEN ELSE

2019-07-29 18:29发布

问题:

I would like to reformat my code without the if then else condition. Is there an easy way to do this? This is just an exemple of code. I think using IF-THEN-ELSE in prolog is weird :\ And I'm looking to get something more recursive cases. Like pattern matching

rules(Param1, Param2) :-
(
    A ->
        B, C, D,    
        (
            E ->  F
        ;
            G, H
        )    
    ;   
        I
).

Edit: Edited my code to look like more what it should look

回答1:

The general translation scheme for

pred(X):-
  ( A -> B
  ; C -> D
  ; G
  ).
pred(Y):- Q.

is

pred(X):- pred1(X).
pred(Y):- Q.

pred1(X):- call(A), !, B.
pred1(X):- call(C), !, D.
pred1(X):- G.

Big thanks to j4n bur53 for pointing out the need for call -- in case there's a cut inside the A or the C!

See also -> documentation.



回答2:

if-then-else are not really weird. They are part of the ISO core standard, defined in 7.8 Control constructs, 7.8.8 (;)/2 - if-then-else and they have the benefit that various Prolog compilation schemes exist.

These Prolog compilation strategies are especially useful if the if-then-else appears in the middle of a clause, since the resulting code usually generates less overhead than when the if-then-else would be moved into a separate auxiliary predicate.

The same holds for disjunction (;)/2. As a rule of thumb I would say it is safe, if there is no if-then-else branch that introduces many new variables compared to the other branches. It then makes sense when the Prolog compiler moves variable creation outside of the if-then-else.

Here is an example where if-then-else, in YAP Prolog, shows quite some performance superiour to other programming styles:

tarai_cut(X,Y,_,Y) :- X=<Y, !.
tarai_cut(X,Y,Z,R) :-
    X1 is X-1, tarai_cut(X1,Y,Z,Rx),
    Y1 is Y-1, tarai_cut(Y1,Z,X,Ry),
    Z1 is Z-1, tarai_cut(Z1,X,Y,Rz),
    tarai_cut(Rx,Ry,Rz,R).

tarai_or(X,Y,Z,R) :- X=<Y, !, R=Y;
    X1 is X-1, tarai_or(X1,Y,Z,Rx),
    Y1 is Y-1, tarai_or(Y1,Z,X,Ry),
    Z1 is Z-1, tarai_or(Z1,X,Y,Rz),
    tarai_or(Rx,Ry,Rz,R).

tarai_if(X,Y,Z,R) :- X=<Y -> R=Y;
    X1 is X-1, tarai_if(X1,Y,Z,Rx),
    Y1 is Y-1, tarai_if(Y1,Z,X,Ry),
    Z1 is Z-1, tarai_if(Z1,X,Y,Rz),
    tarai_if(Rx,Ry,Rz,R). 

The if-then-else version runs fastest:

   YAP 6.3.3 (i686-mingw32): Sun Jan 20 18:27:56 GMTST 2013

   ?- time(tarai_cut(12,6,0,X)).
   % 0.687 CPU in 0.690 seconds ( 99% CPU)
   X = 12

   ?- time(tarai_or(12,6,0,X)).
   0.734 CPU in 0.735 seconds ( 99% CPU)
   X = 12

   ?- time(tarai_if(12,6,0,X)).
   % 0.515 CPU in 0.516 seconds ( 99% CPU)
   X = 12