I changed how the reduction routines work, so I now use the smallest "eval"
routine conceivable, just three lines of code in value.c:

	while (f->T == 0)
		{
		eval(f->L);
		f->L->T(f);
		}

This gives me more flexibility in how these routines work, enabling me to
optimize memory layouts of certain important data types, even on the fly.

For example, a list value which looks like this in memory (using [T,L,R]
notation):

	[0,[0,[reduce_item,0,0],head],tail]

Automatically transforms into this:

	[reduce_item3,head,tail]

Already I'm seeing key tests such as a2.fxl running 10% faster, but I've only
just begun to apply the new techniques.  Not only that, but I removed the built
in version of "fold" (coded in C), because I didn't need that extra complexity
while I was creating this new version, and removing that caused one piece of
a2.fxl to run a little slower.

The new technique also allows plug-in reduction routines to be written more
simply, without as much fussiness with checking the counts and types of
arguments.  For example, the old version of long_add was this:

	value fexl_long_add(value f)
		{
		if (!f->L || !f->L->L) return 0;

		value x = f->L->R;
		value y = f->R;

		if (!arg(type_long,x)) return 0;
		if (!arg(type_long,y)) return 0;

		return Qlong(get_long(x) + get_long(y));
		}

But now it looks much more streamlined:

	static void reduce2_long_add(value f)
		{
		long x = get_long(arg(type_long,f->L->R));
		long y = get_long(arg(type_long,f->R));
		replace(f, Qlong(x + y));
		}

This is helped by the fact that the "arg" routine dies when there's a type
error, instead of return false to the caller.

Another big change I made was to simplify the comparison functions for long,
double, and string.  Formerly I had the branching comparison functions built
right into C, in the form of five argument functions like these:

	long_compare x y lt eq gt
	double_compare x y lt eq gt
	string_compare x y lt eq gt

Now instead I build much simpler comparison functions into C, a two argument
version which compares two values, and returns a long value which is either
negative, zero, or positive:

	long_cmp x y
	double_cmp x y
	string_cmp x y

When you want to branch three ways on the result, I have a function in long.c
called "order", which takes a long value, and returns one of three cases
depending on whether the value is less than, equal to, or greater than zero:

	order x lt eq gt

This new approach greatly simplifies the reduction routines written in C, and
also allowed some pleasant simplifications in the Fexl library (in the "share"
directory: compare.fxl, long.fxl, double.fxl, string.fxl).

In share/fexl/ipc.fxl, I fixed a small usage error in the "spawn" function
where I was calling "close" on a file descriptor without passing in a status
handler.  Inside spawn I simply created a version of "close" which died on a
negative status.

I have always used the two functions "yes" and "no" to handle the concept of
optional values.  Formerly these were written in the Fexl library as:

	\yes = (\val \yes\no yes val)
	\no  = (     \yes\no no)   # Equivalent to F (false)

However, I have now written a built-in version of "yes" in basic.c.  I did that
because it helps simplify other reduction routines, which can now immediately
yield a yes or no result without having to await the arrival of two additional
handlers, one for yes and one for no.  This also enhances efficiency.

In share/fexl/main.fxl I removed the feature of "fprint" which automatically
prints out whole application trees as meta-data.  I just don't want this kind
of magic built into a function like that.  You can always use "show" to do this
explicitly.

In basic.c I removed the built-in definitions for the combinators S, L, and R.
I simply do not need them.