1:- module(type_list,
    2	[
    3	op(100, yf,  []),    % support block notation
    4	op(500, yfx, \\),    % for appending (pseudo SQL ||)
    5	slice_parameters/4,  % slice support for blocks
    6	index_parameters/3   % index support for blocks
    7	]).

arithmetic type support for lists

This module implements a set of functions on lists which can be used in standard arithmetic expressions, including block indexing and slicing (using [] as a postfix operator), concatenation, flatten, fill from a range, etc. It also exports a couple of predicates to support indexing and slicing on other "sequence" types.

The set of list arithmetic functions defined by this module include:

:- arithmetic_function(new/2).        % create
:- arithmetic_function('[|]'/2).      % evaluate list items
:- arithmetic_function([]/1).         % block index
:- arithmetic_function([]/2).
:- arithmetic_function(: /2).         % slice (used with block indexing)
:- arithmetic_function(length/1).     % size or length
:- arithmetic_function(init/2).       % fill any vars
:- arithmetic_function(\\ /2).        % list concat
:- arithmetic_function(flatten/1).    % flattened list
:- arithmetic_function(arange/2).     % list from range(N)
:- arithmetic_function(arange/3).     % list from range(B,E)
:- arithmetic_function(arange/4).     % list from range(B,E,S)

See the ReadMe for this pack for more documentation and examples. */

   32:- use_module(library(arithmetic_types)).   33%%:- current_module(arithmetic_types) -> true ; use_module(library(arithmetic_types)).
   34
   35% Also provides:
   36%  1. Generic slice evaluation (used inside block indexing)
   37%  2. Generic evaluation of list items
   38
   39:- set_prolog_flag(unknown,fail).     % disable autoloading of other function predicates
   40
   41:- arithmetic_function(new/2).        % create
   42:- arithmetic_function('[|]'/2).      % evaluate list items
   43:- arithmetic_function([]/1).         % block index
   44:- arithmetic_function([]/2).   45:- arithmetic_function(: /2).         % slice (used with block indexing)
   46%- arithmetic_function(length/1).     % size or length (directive below)
   47:- arithmetic_function(init/2).       % fill any vars
   48:- arithmetic_function(\\ /2).        % list concat
   49:- arithmetic_function(flatten/1).    % flattened list (directive below)
   50:- arithmetic_function(arange/2).     % list from range(N)
   51:- arithmetic_function(arange/3).     % list from range(B,E)
   52:- arithmetic_function(arange/4).     % list from range(B,E,S)
   53
   54%
   55% Exports
   56%
   57% slice parms
   58slice_parameters(B:E,Len,SBegin,SLen) :-
   59	item_eval(B,Br), (var(Br) -> Br=0 ; integer(Br)),
   60	item_eval(E,Er), (var(Er) -> Er=Len ; integer(Er)),
   61	(Br<0 -> SBegin is Len+Br ; SBegin=Br),
   62	(Er<0 -> SLen is Len+Er-SBegin ; SLen is Er-SBegin).
   63
   64% index parm
   65index_parameters(Ix,Len,I) :-
   66	item_eval(Ix,EIx),
   67	integer(EIx),
   68	(EIx < 0 -> I is Len+EIx ; I = EIx),
   69	I >= 0.
   70
   71% evaluate (largely for efficiency)
   72item_eval(X,X) :- var(X), !.                          % vars OK in lists
   73item_eval(N,N) :- number(N), !.                       % optimization
   74item_eval(X,R) :- 
   75	catch(arithmetic_expression_value(X,R), _, R=X).  % catchall, identity function
   76
   77%
   78% Function: generic slice expression - pass through until used
   79%
   80':'(B,E,B:E). 
   81
   82%
   83% Function: evaluate list items
   84% 
   85'[|]'(X,Xs,[X|Xs]).        % lazy evaluation
   86
   87%
   88% Function: create new list
   89%
   90new(list,Size,L) :- integer(Size), Size >= 0, (nonvar(L) -> is_list(L) ; true), !,
   91	length(L,Size).
   92
   93new(list,Xs,Xs) :- is_list(Xs).
   94
   95%
   96% Function: indexing and slicing
   97%
   98[](L, L) :- is_list(L).
   99[]([I1,I2|IN],T,X) :-  !,      % multi-level index, works on any supported indexing type
  100	T1 is T[I1],               % index one level and recurse
  101	X is T1[I2|IN].
  102[]([B:E],L,X) :- is_list(L),  
  103	length(L,Len),
  104	slice_parameters(B:E,Len,SB,SL), !,
  105	sub_list(L,SB,SL,_,X).
  106[]([Ix], L, R) :- is_list(L), 
  107	length(L,Len),
  108	index_parameters(Ix,Len,I),
  109	% the following uses near constant time arg for lists exceeding some threshold
  110	(I =< 28 -> skip_N(I,L,[X|_]) ; (T=..[$|L], arg(I,T,X))),
  111	item_eval(X,R).  % evaluate selected item
  112    
  113%  sub_atom/5 for lists
  114sub_list(L,Before,Length,After,SubL) :- integer(Before), integer(Length), is_list(L),
  115	skip_N(Before,L,L1),         % remove prefix
  116	next_N(Length,L1,SubL,L2),   % collect sub list and suffix	
  117	length(L2,After),            % length of suffix
  118	!.                           % deterministic
  119
  120skip_N(0,In,In):- !.
  121skip_N(1,[_|In],In):- !.
  122skip_N(N,[_,_|Xs],Out) :-                  % N>0,  % superfluous check
  123	N1 is N-2,
  124	skip_N(N1,Xs,Out).
  125
  126next_N(0,In,[],In) :- !.
  127next_N(1,[X|In],[X],In) :- !.
  128next_N(N,[X1,X2|In],[X1,X2|Out],Rem) :-    % N>0,  % superfluous check
  129	N1 is N-2,
  130	next_N(N1,In,Out,Rem).
  131
  132%
  133% Function: size/length (never called locally, prior calls invoke system:length)
  134%
  135:- redefine_system_predicate(length(_,_)). % permits local redefinition for function
  136
  137length(L,N) :- is_list(L),
  138	system:length(L,N).
  139
  140:- arithmetic_function(length/1).          % size or length
  141
  142%
  143% Function: fill any vars
  144%
  145init(L, Value, L) :- is_list(L),
  146	fill_each(L,Value).
  147
  148fill_each([],_).
  149fill_each([X|Xs],Value) :-
  150	(is_list(X)
  151	 -> fill_each(X,Value)
  152	  ; (var(X) -> X=Value ; true)
  153	),
  154	fill_each(Xs,Value).
  155
  156%
  157% Function: append 2 lists
  158%
  159\\(L1, L2, R) :-  nonvar(L1), is_list(L2),  % guard against ill-formed lists
  160	append_det(L1,L2,R).
  161
  162append_det([], L, L) :- !.  % deterministic, so !
  163append_det([H|T], L, [H|R]) :-
  164	append_det(T, L, R).
  165
  166%
  167% Function: flattened list
  168%
  169flatten(List,FList) :- is_list(List),
  170	lists:flatten(List,FList).
  171
  172:- arithmetic_function(flatten/1).    % flattened list from local flatten/2
  173
  174%
  175% Function: arange/2,3,4
  176%
  177arange(list,N,L) :- number(N), N>0,
  178	E is N-1,
  179	arange_(0,E,1,L).
  180
  181arange(list,B,E,L) :- number(B), number(E),
  182	B>=0, E>B,
  183	arange_(B,E,1,L).
  184
  185arange(list,B,E,S,L) :- number(B), number(E), number(S),
  186	B>=0, E>B, S>0,
  187	arange_(B,E,S,L).
  188
  189arange_(B,E,_S,[]) :- B>E, !.
  190arange_(B,E,S,[B|Vs]) :- 
  191	B1 is B+S,
  192	arange_(B1,E,S,Vs)