250 lines
6.4 KiB
Perl
250 lines
6.4 KiB
Perl
|
/* $Id$
|
||
|
|
||
|
Part of CHR (Constraint Handling Rules)
|
||
|
|
||
|
Author: Tom Schrijvers
|
||
|
E-mail: Tom.Schrijvers@cs.kuleuven.be
|
||
|
WWW: http://www.swi-prolog.org
|
||
|
Copyright (C): 2003-2004, K.U. Leuven
|
||
|
|
||
|
This program is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU General Public License
|
||
|
as published by the Free Software Foundation; either version 2
|
||
|
of the License, or (at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Lesser General Public
|
||
|
License along with this library; if not, write to the Free Software
|
||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
|
||
|
As a special exception, if you link this library with other files,
|
||
|
compiled with a Free Software compiler, to produce an executable, this
|
||
|
library does not by itself cause the resulting executable to be covered
|
||
|
by the GNU General Public License. This exception does not however
|
||
|
invalidate any other reasons why the executable file might be covered by
|
||
|
the GNU General Public License.
|
||
|
*/
|
||
|
|
||
|
% ____ _ ____ _ _
|
||
|
% / ___|___ __| | ___ / ___| | ___ __ _ _ __ (_)_ __ __ _
|
||
|
% | | / _ \ / _` |/ _ \ | | | |/ _ \/ _` | '_ \| | '_ \ / _` |
|
||
|
% | |__| (_) | (_| | __/ | |___| | __/ (_| | | | | | | | | (_| |
|
||
|
% \____\___/ \__,_|\___| \____|_|\___|\__,_|_| |_|_|_| |_|\__, |
|
||
|
% |___/
|
||
|
%
|
||
|
% To be done:
|
||
|
% inline clauses
|
||
|
|
||
|
:- module(clean_code,
|
||
|
[
|
||
|
clean_clauses/2
|
||
|
]).
|
||
|
|
||
|
:- use_module(library(dialect/hprolog)).
|
||
|
|
||
|
clean_clauses(Clauses,NClauses) :-
|
||
|
clean_clauses1(Clauses,Clauses1),
|
||
|
merge_clauses(Clauses1,NClauses).
|
||
|
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
% CLEAN CLAUSES
|
||
|
%
|
||
|
% - move neck unification into the head of the clause
|
||
|
% - drop true body
|
||
|
% - specialize control flow goal wrt true and fail
|
||
|
%
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
|
||
|
clean_clauses1([],[]).
|
||
|
clean_clauses1([C|Cs],[NC|NCs]) :-
|
||
|
clean_clause(C,NC),
|
||
|
clean_clauses1(Cs,NCs).
|
||
|
|
||
|
clean_clause(Clause,NClause) :-
|
||
|
( Clause = (Head :- Body) ->
|
||
|
clean_goal(Body,Body1),
|
||
|
move_unification_into_head(Head,Body1,NHead,NBody),
|
||
|
( NBody == true ->
|
||
|
NClause = NHead
|
||
|
;
|
||
|
NClause = (NHead :- NBody)
|
||
|
)
|
||
|
; Clause = '$source_location'(File,Line) : ActualClause ->
|
||
|
NClause = '$source_location'(File,Line) : NActualClause,
|
||
|
clean_clause(ActualClause,NActualClause)
|
||
|
;
|
||
|
NClause = Clause
|
||
|
).
|
||
|
|
||
|
clean_goal(Goal,NGoal) :-
|
||
|
var(Goal), !,
|
||
|
NGoal = Goal.
|
||
|
clean_goal((G1,G2),NGoal) :-
|
||
|
!,
|
||
|
clean_goal(G1,NG1),
|
||
|
clean_goal(G2,NG2),
|
||
|
( NG1 == true ->
|
||
|
NGoal = NG2
|
||
|
; NG2 == true ->
|
||
|
NGoal = NG1
|
||
|
;
|
||
|
NGoal = (NG1,NG2)
|
||
|
).
|
||
|
clean_goal((If -> Then ; Else),NGoal) :-
|
||
|
!,
|
||
|
clean_goal(If,NIf),
|
||
|
( NIf == true ->
|
||
|
clean_goal(Then,NThen),
|
||
|
NGoal = NThen
|
||
|
; NIf == fail ->
|
||
|
clean_goal(Else,NElse),
|
||
|
NGoal = NElse
|
||
|
;
|
||
|
clean_goal(Then,NThen),
|
||
|
clean_goal(Else,NElse),
|
||
|
NGoal = (NIf -> NThen; NElse)
|
||
|
).
|
||
|
clean_goal((G1 ; G2),NGoal) :-
|
||
|
!,
|
||
|
clean_goal(G1,NG1),
|
||
|
clean_goal(G2,NG2),
|
||
|
( NG1 == fail ->
|
||
|
NGoal = NG2
|
||
|
; NG2 == fail ->
|
||
|
NGoal = NG1
|
||
|
;
|
||
|
NGoal = (NG1 ; NG2)
|
||
|
).
|
||
|
clean_goal(once(G),NGoal) :-
|
||
|
!,
|
||
|
clean_goal(G,NG),
|
||
|
( NG == true ->
|
||
|
NGoal = true
|
||
|
; NG == fail ->
|
||
|
NGoal = fail
|
||
|
;
|
||
|
NGoal = once(NG)
|
||
|
).
|
||
|
clean_goal((G1 -> G2),NGoal) :-
|
||
|
!,
|
||
|
clean_goal(G1,NG1),
|
||
|
( NG1 == true ->
|
||
|
clean_goal(G2,NGoal)
|
||
|
; NG1 == fail ->
|
||
|
NGoal = fail
|
||
|
;
|
||
|
clean_goal(G2,NG2),
|
||
|
NGoal = (NG1 -> NG2)
|
||
|
).
|
||
|
clean_goal(Goal,Goal).
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
move_unification_into_head(Head,Body,NHead,NBody) :-
|
||
|
conj2list(Body,BodyList),
|
||
|
move_unification_into_head_(BodyList,Head,NHead,NBody).
|
||
|
|
||
|
move_unification_into_head_([],Head,Head,true).
|
||
|
move_unification_into_head_([G|Gs],Head,NHead,NBody) :-
|
||
|
( nonvar(G), G = (X = Y) ->
|
||
|
term_variables(Gs,GsVars),
|
||
|
( var(X), ( \+ memberchk_eq(X,GsVars) ; atomic(Y)) ->
|
||
|
X = Y,
|
||
|
move_unification_into_head_(Gs,Head,NHead,NBody)
|
||
|
; var(Y), (\+ memberchk_eq(Y,GsVars) ; atomic(X)) ->
|
||
|
X = Y,
|
||
|
move_unification_into_head_(Gs,Head,NHead,NBody)
|
||
|
;
|
||
|
Head = NHead,
|
||
|
list2conj([G|Gs],NBody)
|
||
|
)
|
||
|
;
|
||
|
Head = NHead,
|
||
|
list2conj([G|Gs],NBody)
|
||
|
).
|
||
|
|
||
|
|
||
|
conj2list(Conj,L) :- %% transform conjunctions to list
|
||
|
conj2list(Conj,L,[]).
|
||
|
|
||
|
conj2list(G,L,T) :-
|
||
|
var(G), !,
|
||
|
L = [G|T].
|
||
|
conj2list(true,L,L) :- !.
|
||
|
conj2list(Conj,L,T) :-
|
||
|
Conj = (G1,G2), !,
|
||
|
conj2list(G1,L,T1),
|
||
|
conj2list(G2,T1,T).
|
||
|
conj2list(G,[G | T],T).
|
||
|
|
||
|
list2conj([],true).
|
||
|
list2conj([G],X) :- !, X = G.
|
||
|
list2conj([G|Gs],C) :-
|
||
|
( G == true -> %% remove some redundant trues
|
||
|
list2conj(Gs,C)
|
||
|
;
|
||
|
C = (G,R),
|
||
|
list2conj(Gs,R)
|
||
|
).
|
||
|
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
% MERGE CLAUSES
|
||
|
%
|
||
|
% Find common prefixes of successive clauses and share them.
|
||
|
%
|
||
|
% Note: we assume that the prefix does not generate a side effect.
|
||
|
%
|
||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
|
||
|
merge_clauses([],[]).
|
||
|
merge_clauses([C],[C]).
|
||
|
merge_clauses([X,Y|Clauses],NClauses) :-
|
||
|
( merge_two_clauses(X,Y,Clause) ->
|
||
|
merge_clauses([Clause|Clauses],NClauses)
|
||
|
;
|
||
|
NClauses = [X|RClauses],
|
||
|
merge_clauses([Y|Clauses],RClauses)
|
||
|
).
|
||
|
|
||
|
merge_two_clauses('$source_location'(F1,L1) : C1,
|
||
|
'$source_location'(_F2,_L2) : C2,
|
||
|
Result) :- !,
|
||
|
merge_two_clauses(C1,C2,C),
|
||
|
Result = '$source_location'(F1,L1) : C.
|
||
|
merge_two_clauses((H1 :- B1), (H2 :- B2), (H :- B)) :-
|
||
|
H1 =@= H2,
|
||
|
H1 = H,
|
||
|
conj2list(B1,List1),
|
||
|
conj2list(B2,List2),
|
||
|
merge_lists(List1,List2,H1,H2,Unifier,List,NList1,NList2),
|
||
|
List \= [],
|
||
|
H1 = H2,
|
||
|
call(Unifier),
|
||
|
list2conj(List,Prefix),
|
||
|
list2conj(NList1,NB1),
|
||
|
( NList2 == (!) ->
|
||
|
B = Prefix
|
||
|
;
|
||
|
list2conj(NList2,NB2),
|
||
|
B = (Prefix,(NB1 ; NB2))
|
||
|
).
|
||
|
|
||
|
merge_lists([],[],_,_,true,[],[],[]).
|
||
|
merge_lists([],L2,_,_,true,[],[],L2).
|
||
|
merge_lists([!|Xs],_,_,_,true,[!|Xs],[],!) :- !.
|
||
|
merge_lists([X|Xs],[],_,_,true,[],[X|Xs],[]).
|
||
|
merge_lists([X|Xs],[Y|Ys],H1,H2,Unifier,Common,N1,N2) :-
|
||
|
( H1-X =@= H2-Y ->
|
||
|
Unifier = (X = Y, RUnifier),
|
||
|
Common = [X|NCommon],
|
||
|
merge_lists(Xs,Ys,H1/X,H2/Y,RUnifier,NCommon,N1,N2)
|
||
|
;
|
||
|
Unifier = true,
|
||
|
Common = [],
|
||
|
N1 = [X|Xs],
|
||
|
N2 = [Y|Ys]
|
||
|
).
|