
/* tuple.q: additional tuple functions
   $Id: tuple.q,v 1.3 2007/10/03 13:03:48 agraef Exp $ */

/* This file is part of the Q programming system.

   The Q programming system 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, or (at your option)
   any later version.

   The Q programming system 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 General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

include stdlib;

/* Construct pairs and triples. */

public pair X Y, triple X Y Z;

pair X Y		= (X,Y);
triple X Y Z		= (X,Y,Z);

/* Return the first, second and third element of a tuple. */

public fst Xs, snd Xs, trd Xs;

fst (X|_)		= X;
snd (_,Y|_)		= Y;
trd (_,_,Z|_)		= Z;

/* Create a tuple of given length. */

public mktuple X N;

mktuple X N:Int		= tuple (mklist X N);

/* Concatenate a list of tuples. */

public tuplecat Xs;

tuplecat Xs:List	= foldl (++) () Xs;

/* Overloaded list operations (cf. stdlib.q). */

append () Y		= (Y,);
append (X|Xs) Y		= (X|append Xs Y);

cat Xs:Tuple		= cat Xs where Xs:List = list Xs;
cat [Xs:Tuple|Xss]	= cat [Xs|Xss] where Xs:List = list Xs;

cons X Xs:Tuple		= (X|Xs);

null ()			= true;
null _:Tuple		= false otherwise;

pop (_|Xs)		= Xs;

push Xs:Tuple X		= (X|Xs);

reverse Xs:Tuple	= foldl push () (list Xs);

top (X|_)		= X;

/* The map and do functions on proper tuples are a bit more involved since we
   want them to run in constant space. */

private tupledo I N F Xs;

tupledo I:Int N:Int F Xs:Tuple
			= F (Xs!I) || tupledo (I+1) N F Xs if I<N;
			= () otherwise;

do F Xs:Tuple		= tupledo 0 N F Xs where N:Int = #Xs;

private tupledowith I N M F Xs Ys, tupledowith3 I N M P F Xs Ys Zs;

tupledowith I:Int N:Int M:Int F Xs:Tuple Ys:Tuple
			= F (Xs!I) (Ys!I) ||
			  tupledowith (I+1) N M F Xs Ys
			    if (I<N) and then (I<M);
			= () otherwise;

tupledowith3 I:Int N:Int M:Int P:Int F Xs:Tuple Ys:Tuple Zs:Tuple
			= F (Xs!I) (Ys!I) (Zs!I) ||
			  tupledowith3 (I+1) N M P F Xs Ys Zs
			    if (I<N) and then (I<M) and then (I<P);
			= () otherwise;

dowith F Xs:Tuple Ys:Tuple
			= tupledowith 0 N M F Xs Ys
			    where N:Int = #Xs, M:Int = #Ys;

dowith3 F Xs:Tuple Ys:Tuple Zs:Tuple
			= tupledowith3 0 N M P F Xs Ys Zs
			    where N:Int = #Xs, M:Int = #Ys, P:Int = #Zs;

private tuplemap I Ys F Xs;

tuplemap I:Int Ys:List F Xs:Tuple
			= tuplemap (I-1) [F (Xs!I)|Ys] F Xs if I>=0;
			= tuple Ys otherwise;

map F Xs:Tuple		= tuplemap (N-1) [] F Xs where N:Int = #Xs;

/* Default rules to handle the case of improper tuples. These are treated
   exactly like lists. */

do F ()			= ();
do F (X|Xs)		= F X || do F Xs;

dowith F (X|Xs) (Y|Ys)	= F X Y || dowith F Xs Ys;
dowith F _:Tuple _:Tuple
			= () otherwise;

dowith3 F (X|Xs) (Y|Ys) (Z|Zs)
			= F X Y Z || dowith3 F Xs Ys Zs;
dowith3 F _:Tuple _:Tuple _:Tuple
			= () otherwise;

map F ()                = ();
map F (X|Xs)            = (F X|map F Xs);
