#
# RationalFunction(D,x); or RationalFunction(D,[x1,x2,...,xn])
#
# Creates a domain of rational functions in x (x1, x2, ..., xn) over D
# an Gcd domain.  D may be a field.  Examples
#
# Z(x) == RationalFunction(Z,x)
# Q(x) == RationalFunction(Q,x)
# GF(2^10)(x,y) == RationalFunction( GaloisField(2,10), [x,y] )
#
# Author: MBM 1989
# 
RationalFunction := proc() local R,P,x,v,n,Q;

	R := args[1];
	x := args[2];
	if not type(x,list) then x := [x] fi;
	n := nops(x);

	if not type(x,list({name,function})) then
		ERROR(`2nd argument must be a list of names`) fi;
	if not type(R,Domain) then
		ERROR(`1st argument must be a Domain`) fi;
	if not hasCategory(R,GcdDomain) then
		ERROR(`1st argument must be a Gcd domain`) fi;

	P := R;
	for v in x do P := DenseUnivariatePolynomial(eval(P,1),v) od;
	Q := QuotientField(P);
	env := ['QQ'=Q, 'PP'=P, 'RR'=R, 'N'=n];
	defOperation( Eval, [Q, R$n] &-> Q, Q );
	defOperation( Cons, R &-> Q, Q );
	Q[Cons] := subs( env, proc(c,n,R)
		if n = 0 then c
		else R[Constant]( QQ[Cons](c,n-1,R[CoefficientRing]) )
		fi
	    end);
	Q[Constant] := subs( env, proc(c)
		QQ[Slash]( QQ[Cons](c,N,PP), PP[1] )
	    end);
	Q[ID] := P;
	Q[Eval] := subs( env, proc(a) local n,d,i,x,R;
		n := QQ[Numer](a); d := QQ[Denom](a);
		R := PP;
		for i from N by -1 to 1 do
		    C := R[CoefficientRing];
		    x := QQ[Cons](args[i+1],i-1,C);
		    n := R[Eval](n,x); d := R[Eval](d,x);
		    R := C;
		od;
		QQ[Slash]( QQ[Cons](n,N,PP), QQ[Cons](d,N,PP) );
	    end);
	op(Q)
end:
save `RF.m`;
quit
