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