eX version 0.4b User's Manual                         File eXMan07.txt
(C) Copyright 1995, 1996 William E. Wilgus III.   All rights reserved.



Functions and Filters
 
eX has a rather large library of functions.  I'm not much of a
mathemetician and I hate trying to figure out what math I need to do
and then looking up how to do it.  With eX's fairly complete set of
math functions, I can just scan the manual to chose the function and
plug in the arguments.  It does, however, still lack a function to
calculate a moon shot for an '82 Toyota with all the in-laws aboard. 

I'm quite a bit better at manipulating strings.  But the few primative
string functions included in most languages leave me exasperated at
the amount of coding I usually have to do in order to accomplish what
has to be done.  That's why eX's string functions are as inclusive as
they are.  My favorite trick turns `digital equipment corporation'
into `EDC':

  swimL(exceptS onlyU Pcase "digital equipment corporation", "E", 1)

Four functions and I can induce chaos in the financial markets!  I'll
leave the explanation---of the eX functions---as an exercise for you 
to complete. 

Unlike the previously introduced data class filters, the filters
discussed in this chapter are functions and process the data they
recieve.  I make the distinction to point out the processing
difference between the two function types and broach the subject here
to aid comprehension of this chapter.  Quite simply, a filter function
employs an un-parenthesized single argument and recieves the argument
value directly from the eX interpreter in the same manner as an
operator.  Therefore, whatever eX allows you to do between an operator
and its right-hand value (which is almost anything), you can do
between a filter function and its argument.  You might also like to
know that you can revert a filter function to a function by simply
parenthesizing its argumen5, omitting all whitespace between the function
name and the left parens.  

A function, on the other hand, employs a parenthesized argument.  eX
interprets the argument(s) within the parens and passes them
indirectly by value to the function, which may perform further
processing of the argument(s) prior to performing the function.  This
strategy precludes few possibilities as far as what you can do in a
function argument and explains why you sometimes may have to do a bit
more in a (parenthesized) function argument, particularly when using
an aggregation as an argument element.  


Functions

No whitespace may appear between a function identifier and its
parenthesized argument.  No whitespace is required between an argument
delimiting parens and the adjacent argument.  Argument elements must
be seperated by a comma that is followed by whitespace. 

               function(argument1, argument2)


Parenthesized arguments are evaluated in plane -2 to preclude
accumulator `contamination'.  On entry to a parenthesized argument,
the current plane and level is saved for recall on exit from the
argument, and the plane is changed to -2 and the level is changed to
0, then 1.  In the event the plane is already -2 on entry to a
parenthesized argument, the level is merely incremented.  Once the
proper accumulator plane, level is attained, the accumulators are
nulled.  But note that a parenthesized function argument does not in
any way function as an aggregation and no accumulator push, hold or
pop commands are available.  (I'll return to argument aggregation
shortly.)  

While on the subject of a parenthesized argument's accumulator plane 
and level, you might wish to recall eX's `fPlane' and `fLevel' functions,
which return the plane and level of the current function, i.e. the
plane and level of the function name.  The point I'm getting at is
that if you wish to address an accumulator that is at the plane and
level of the function name within its parenthesized argument, you
can't use @(fPlane, fLevel) because they return the plane and level of
the accumulator token, @. 

Function arguments are passed by value.  Values generated in a
parenthesized argument are passed to the function only when a comma
(argument seperator) or argument terminating delimiter (right parens)
is encountered---the value passed being that of the term immediately 
preceding the comma or right parens.  This explains why---with a
limitation for the assignable string functions discussed shortly---you
can put code that has nothing to do with the function in front of a
component argument: 

  cir(show "Hello world!" PresentValue#, FutureValue#, InterestRate#)

(Cir is the financial function `Compound Interest Rate'.)  Note that the
argument seperating comma also resets the accumulators for the plane
and level to 0.0 and "". 

Aggregations (including tests and loops) may be employed in
parenthesized arguments to calculate argument values.  Except for
test structures, the appropriate data class filter must precede the
aggregation to preclude the function from receiving an argument of an
incorrect data class.  

             StringFunction($ (Expression))
             NumericFunction(# (Expression))


Accumulation may be performed in a parenthesized argument, but it's a
messy process.  First, accumulation must be initiated manually with
either an addition or subtraction operation.  Once the operations have
been completed, the appropriate accumulator must be addressed to pass
the accumulation to the argument.

           function(+ "testing" - "ing" @$, + 1 + 2 @#)

This explains why operated addresses were created.  They're much
`cleaner' in an argument:  

               function("testing" % - "ing", 1 % + 2)

(The result of the string subtraction is "test".)


Some functions require that a data entity's identifier rather than its
value be passed to the argument (reference versus address), and in
these cases, the identifier must be expressed as a literal, unless the
argument element is given as a string data entity whose value is the 
identifier of the data entity to be given to the function (indirect
object data entity specification).  

               function("identifier")
               function($IdentifierValueVariable := "identifier")

Yes, the assignment is perfectly legal. 

Some functions, including filters, allow the programmer to specify the
data type of its output, either string or numeric, through the use of
a suffix.  The string suffix is `$', and the numeric suffix is `#'.  The
suffix must immediately follow the function identifier (i.e. no
whitespace may intervene).  Whitespace may not appear between a
function suffix and a parenthesized argument, but must appear between
a function suffix and a filter function (un-parenthesized) argument.  
A data type suffix used with a function that lacks the option is
ignored.  
 
                         function$(argument)
                         function# argument

Filters

Unless stated otherwise for specific functions, the argument of a
function that employs a single argument element may be left
un-parenthesized, and if left un-parenthesized, must be seperated from
the function name, or its data class suffix, by whitespace.  The
functions that do not allow the un-parenthesized argument form are
generally those that use a default argument if the argument is
omitted. 

                    function argument

The function then becomes a filter function.  

Un-parenthesized arguments may take the form of an aggregation, which
must be preceded by an eev filter if the function will accept either a
numeric or a string argument. 

               function # (argument)
               function $ (argument)

However, some eX functions might accept both a numeric and string
argument simultaneously, and in this case, an eev filter is not
required and may be in-consistent with producing correct results from
the function.

 
One or more operators may be employed between a function and its un 
parenthesized argument.  The operation(s) are performed using the
argument as the right-hand operator (and the accumulators as the
left-hand operator) and then the (original value of the) argument is
passed to the function. 

                  function *# + argument

Data class filters may also be used between a function and its
un-parentisized argument; but make sure you don't kill the data
class(es) a function requires!  NOTE that since a filter function does
not provide its output value until after it recieves its argument
value, an operated address between the filter and its argument 
(function % + argument) will not work because there is no left-hand
operand for it to use.  An operated address may, of course, be used to
provide the argument. 
  

String Functions and Assignment
 
The following discussion uses the substring function 

                left(string$, characters#)

which returns the left-most characters# within string$. 

The assignable string functions, if given a string literal rather than
a data entity as an argument, return the `post assignment' value of
the argument eev$, rather than the value assigned.  Given 

                 $String = "123456789",    

               left($String, 5) := "abcde"

returns `abcde' and $String will now equal `abcde6789'.  
However    

               left("abcde6789", 5) := "12345"

will return `123456789'.  The literal will, of course, still be 
`abcde6789'.   This was done to make intermediate programming steps
un-necessary.  This trick can also be `pulled' with a data entity by
the following  

               left($ ($StringDataEntity), 5) := "12345"

The eX interpreter tricked the function into thinking the argument was
a literal.  
 
If no assignment is made, these functions return the usual.  They are:

               asc       nTerm     right
               anTerm    has       subst
               asc       left      swimL
               aTerm     match     swimR
               bit       mid       term
               LastPos   opos

NOTE that currently none of these functions may employ any of the
others as their first argument if the function is an assignment
object, and subst, swimL and swimR are assignments in themselves. 

Since assignments are permitted wherever a data entity may appear, the
first example in this section could have been written as

               left($String := "123456789", 5) := "abcde"

and would produce identical results.  Multiple assignments are
permitted as well.  Just remember that the first data entity
encountered in the function object argument (i.e., the first argument
in all the assignable functions) is the one that is assigned.  In 

     left($String := $AnotherString := "123456789", 5) := "abcde"

the terminal value of $AnotherString is `123456789'; otherwise the
results are the same as the preceding.  BUT! In 

               left(show $y $x := "123", 2) := "ab"

the function returns the value `ab' and assigns it to the left two 
characters of $y, not $x---its value stays at 123!  How I really
wanted to write the above was 

               left($x := "123", show $y 2) := "ab"

The following would have been worse and crashed eX: 

             left(show _y $x := "123", 2) := "ab" 

