1 % (c) 2009-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(tools_lists,
6 [count_occurences/2,
7 ord_member_nonvar_chk/2,
8 ord_select_nonvar_chk/3,
9 ord_update_nonvar/4,
10 delete_first/3,
11 length_greater/2,
12 length_less/2,
13 member_nonvar_list/2,
14 exclude_count/4,
15 include_maplist/3,
16 optimized_nth1/3,
17 remove_dups_keep_order/2,
18 is_list_simple/1,
19 get_member_option/3,
20 convlist_max/4,
21 common_prefix_atom/2
22 ]).
23
24 :- meta_predicate exclude_count(1,-,-,-).
25 :- meta_predicate exclude_count_aux(-,1,-,-,-).
26 :- meta_predicate convlist_max(2,-,-,-).
27 :- meta_predicate conv_aux(-,2,-,-).
28 :- meta_predicate include_maplist(2,-,-).
29
30 :- use_module(module_information).
31
32 :- module_info(group,infrastructure).
33 :- module_info(description,'A few utilities on lists seperated out from tools.pl to avoid cyclic module dependencies.').
34
35
36 % self-check in tools to avoid dependency on self_check module
37 %:- assert_must_succeed((tools:count_occurences([a,b,a,a,b],R),R == [a-3,b-2])).
38 :- use_module(library(avl), [avl_fetch/2, avl_fetch/3, avl_to_list/2, avl_store/4, empty_avl/1]).
39 :- use_module(library(lists), [nth1/3]).
40
41 % count number of occurences inside a list
42 count_occurences(L,R) :- empty_avl(E), count_occ_aux(L,E,R).
43 count_occ_aux([Term|T],A,Res) :- (avl_fetch(Term,A,Count) -> C is Count+1 ; C = 1),
44 avl_store(Term,A,C,A2),
45 count_occ_aux(T,A2,Res).
46 count_occ_aux([],A,L) :- avl_to_list(A,L).
47
48 % like ord_member but also allows nonvar lookup terms
49 % note that this test fails for ord_member:
50 %:- assert_must_succeed((tools_lists:ord_member_nonvar_chk(p(b,X),[p(a,c),p(b,d)]),R == d)).
51 ord_member_nonvar_chk(X, [H|T]) :-
52 (X=H -> true
53 ; X @>H -> ord_member_nonvar_chk(X,T)).
54
55 :- use_module(library(lists), [select/3]).
56
57 % in contrast to delete/3 we delete only first occurence
58 delete_first(List,X,NewList) :- select(X,List,Del),!,NewList=Del.
59 delete_first(L,_,L).
60
61
62
63 %:- assert_must_succeed((tools_lists:ord_select_nonvar_chk(b,[a,b,c,d],R),R == [a,c,d])).
64 ord_select_nonvar_chk(X, [H|T], Res) :-
65 (X=H -> Res=T
66 ; X @>H -> Res=[H|TR], ord_select_nonvar_chk(X,T,TR)).
67
68 %:- assert_must_succeed((tools_lists:ord_update_nonvar(b(_),[a(x),b(x),d(x)],b(y),R),R == [a(x),b(y),d(x))).
69 %:- assert_must_succeed((tools_lists:ord_update_nonvar(b(_),[a(x),d(x)],b(y),R),R == [a(x),b(y),d(x))).
70 ord_update_nonvar(_, [], Y, Res) :- !, Res = [Y].
71 ord_update_nonvar(X, [H|T], Y, Res) :-
72 (X=H -> Res=[Y|T]
73 ; X @>H -> Res=[H|TR], ord_update_nonvar(X,T, Y, TR)
74 ; Res = [Y,H|T]).
75
76
77 % length_greater([1,2,3],1)
78 length_greater(_,X) :- X<0,!.
79 length_greater([_|T],X) :- X1 is X-1, length_greater(T,X1).
80
81
82 % length_less([1,2,3],4)
83 length_less([],Nr) :- Nr>0.
84 length_less([_|T],X) :- X>1, X1 is X-1, length_less(T,X1).
85
86
87 % a version of member that stops at a variable list tail
88 member_nonvar_list(X,List) :- nonvar(List), List=[H|T],
89 (X=H ; member_nonvar_list(X,T)).
90
91 % a version of exclude with counts the number of excluded items
92 exclude_count(Pred,List,ResList,Excluded) :-
93 exclude_count_aux(List,Pred,ResList,0,Excluded).
94 exclude_count_aux([],_,[],Acc,Acc).
95 exclude_count_aux([H|T],Pred,Res,Acc,Excluded) :-
96 (call(Pred,H)
97 -> Res = RT, Acc1 is Acc+1
98 ; Res = [H|RT], Acc1 = Acc
99 ), exclude_count_aux(T,Pred,RT,Acc1,Excluded).
100
101 % a combination of include and maplist
102 include_maplist(_,[],[]).
103 include_maplist(Pred,[H|T],[MH|MT]) :-
104 call(Pred,H,MH),!,
105 include_maplist(Pred,T,MT).
106 include_maplist(Pred,[_|T],Res) :- include_maplist(Pred,T,Res).
107
108 % a version of nth1 which has no choice point for singleton lists
109 optimized_nth1(Nr,[Single|T],Res) :- T==[], !, Nr=1,Res=Single. % avoid a pending choice point on the stack
110 optimized_nth1(Nr,Whens,Res) :- nth1(Nr,Whens,Res).
111
112
113 % remove_dups version which keeps order of original elements
114 remove_dups_keep_order([],[]).
115 remove_dups_keep_order([H|T],[H|Res]) :- empty_avl(E), avl_store(H,E,true,A1),
116 rem_dups(T,A1,Res).
117
118 rem_dups([],_,[]).
119 rem_dups([H|T],AVL,Res) :-
120 (avl_fetch(H,AVL) -> rem_dups(T,AVL,Res)
121 ; Res=[H|TRes],
122 avl_store(H,AVL,true,AVL1),
123 rem_dups(T,AVL1,TRes)).
124
125 /* Checks if the argument is a list, but unlike is_list/1 it just
126 checks the head and does not iterate through the list */
127 is_list_simple([]).
128 is_list_simple([_|_]).
129
130
131 % useful to extract an equality from an unsorted list of options:
132 get_member_option(Opt,List,Value) :- member(Equality,List), binding(Equality,Opt,Value).
133 binding('='(Opt,Val),Opt,Val).
134 binding('/'(Opt,Val),Opt,Val).
135
136
137
138 % a version of convlist that returns at most Max solutions
139 convlist_max(Pred,Max,List,Res) :-
140 (Max>0 -> conv_aux(List,Pred,Max,Res) ; Res=[]).
141 conv_aux([],_,_,[]).
142 conv_aux([H|T],Pred,Max,Res) :-
143 (call(Pred,H,HX)
144 -> Res=[HX|TX],
145 (Max>1 -> M1 is Max-1, conv_aux(T,Pred,M1,TX)
146 ; TX=[])
147 ; conv_aux(T,Pred,Max,Res)).
148
149
150 % common prefix of a list of atoms
151 % common_prefix_atom([ab,ac],R) -> R=a
152 common_prefix_atom([H],Res) :- !, Res=[H]. % single completion
153 common_prefix_atom([H|T],Res) :- atom_codes(H,Hs), com_all(T,Hs,ResC), atom_codes(Res,ResC).
154
155 com_all([],H,H).
156 com_all([H|T],PrevPrefix,Res) :- atom_codes(H,Hs), common_prefix(Hs,PrevPrefix,NewPrefix),
157 com_all(T,NewPrefix,Res).
158
159 common_prefix([H|T1],[H|T2],[H|Res]) :- !, common_prefix(T1,T2,Res).
160 common_prefix(_,_,[]).