NAME
	functions - an overview

SYNOPSYS
	CREATION
	function func
	function &func(args)
	function ob->func
	function &ob->func(args)

	function &->func(args)

	function operator(BINOP)

	USE
	mixed func(args)

	OPERATORS
	function foo @ bar

DESCRIPTION
	A function variable is declared by
		function f;
	This variable, f, can then be assigned any value
	which is a function.  A function value is either
	just the name of a function, e.g. foo, or a partial
	application (see below), e.g. &foo(1).  I.e. assigning
	a value to the function variable `f' could be done
	by
		f = foo;

	A function variable can be used as an ordinary function
	name, so calling the function assign to `f' would be
	done by
		f(args);

	Functions are just like any other value, so they can be
	put in variable, in arrays, or in mappings.  They can not,
	however, be saved to files and be read back.

	In the forms  ob->func  and  &ob->func(args)  the ob
	part may be an object or a string (the file name for
	the object) just as in and ordinary call  ob->func(args).

	There are really three kinds of functions in LPC, efuns,
	simul efuns, and lfuns.  All of these can be used as
	function values.  If an lfun is used the function value
	will contain information about what object the lfun
	belongs to in order to call the right function at function
	application time.

	Partial application
	-------------------
	It is sometimes useful to give a function some of its arguments
	at a time.  The partial application syntax allows you to
	so this.  An example:

		int foo(int x, int y) { return x*x - y; }

		function f;

		/* different ways of using foo: */
		f = &foo(2,);		/* "freeze" the first argument to 2 */
		write(f(1));		/* 1 is the second arg to foo, */
					/* i.e. foo(2,1) is calculated, */
					/* and 3 is printed. */

		f = &foo(,3);		/* "freeze" the second argument */
		write(f(4));		/* 4 is the first arg to foo, */
					/* i.e. foo(4,3) is calculated */
					/* and 13 is printed, */

		f = &foo(1,2);		/* freeze both, but don't call foo */
		write(f());		/* foo(1,2) is calculated */
					/* and -1 is printed, */

		f = &foo();		/* don't freeze any arguments */
		f = foo;		/* this does the same thing */

	Any combination of arguments can be given.  The missing arguments
	are simply left out from the (partial) application.
	Trailing commas may be omitted, so e.g., &foo(2,) can be
	written as &foo(2).
	When the function is called the missing arguments are filled
	in by the ones given in the application.
	A partially applied function may, of course, also be used
	in a further partial application. E.g.
		f = &bar(2,,,5);
		g = &f(3);
		g(4);			/* will call bar(2,3,4,5) */


	A convenient way to combine functions is function composition.
	The function composition operator is called @.  It is simply
	defined to behave in the following way: 
	if  h = f @ g  then  h(x) = f(g(x)).

	A real example (with thanks to Gorboth and Alcides):
	We would like to print the name of all players that
	are logged on from Sweden.

	ps = filter(users(), 
		    &wildmatch("*.se") @ lower_case @ query_ip_name)
	     ->query_name());

	How does it work?
	users() gives us an array of objects representing all users.
	From this we would like to pick out those from Sweden.  We
	do this by filtering the array.  The filter function is
	a composition that does the following:
		- query_ip_name	extracts the machine name
				e.g. dry.mu.Caltech.edu, algonet.SE
		- lower_case	makes sure all the names are in lower case
				e.g. dry.mu.caltech.edu, algonet.se
		- wildmatch	will give a 1 for those that match the
				pattern ("*.se") and a 0 for the others.
				e.g. 0, 1
	Filter will keep those where the function returned 1, i.e.
	those from Sweden.  We now have an array with objects for
	the swedish players, we now simple ask for their names by
	using the whole array to the left of ->query_name().
	

	The form &->func(args) denotes a function that first expects
	an object, and when given this object it will call func in it.
	Example

		function f;
		f = &->query_wiz_level();

		write(f(this_player()));	/* prints the level of the player */
		/* write the names of all wizards that are logged on */
		write(implode(filter(users(), &->query_wiz_level())->query_name(), " "));


	Operators
	---------
	Many (but not all) binary operators can be turned into
	functions by writing  operator(BINOP)  where BINOP
	is one of the allowed operators.
	For example

		function f;
		f = operator(+);	/* f is now the adding function */
		write(f(2,3));		/* prints 5 */

		f = &operator(-)(,1);	/* f is now the function that
					   subtracts 1 */
		write(f(43));		/* prints 42 */

	This is mainly useful when combined with other functions
	with function composition.
	Example: To filter out all strings of length 5 from an array
	of strings you can write
		filter(arr, &operator(==)(5) @ strlen);

	The operators that can be used in this way are
	+, -, *, /, %, &, |, ^, >>, <<, <, >, <=, >=, ==, !=, []

	The function  operator([])  corresponds to then indexing
	opartion, i.e.  operator([])(x,y) == x[y]
	

SEE ALSO
	applyv, papplyv, mkfunction
	add_action, ed, filter, input_to, map, set_alarm


The following is a slightly more explanitory version of the above.

Using the function type:


1. Declaration:
   function variables are declared in this way:

     function f;

   at this point "f" may be assigned a value that is a function (efun,
   lfun, etc.). 


2. Assignment

   A value can be assigned to a function variable in this manner:

     f = &write();  

   The above assigns the function write to the variable f.  


3. Calling functions using function variables

   Starting with the example above,

     function f = &write();

   we have the function write assigned to a function variable, f.
   At this point, the function assigned to f can be called using standard
   notation:

     f("Hello!\n");

   In this case, the above is identical to 

     write("Hello!\n");


   Here is another, (barely) more useful example:

     void func1() { /* some code */ }

     void func2() { /* some code */ }

     void func3() { /* some code */ }

     void call_random_func() 
     {
       function *funcs = ({ &func1(), &func2(), &func3() });
  
       function_to_call = funcs[random(3)];

       function_to_call();
     }

   Given the code above, calling call_random_func() would result in
   one of the func?() functions being called at random.

   Notice that arrays of functions are perfectly legal.


4. "Freezing" arguments

   When you assign to a function variable, permanent arguments can
   be bound to the function, so that they don't have to be explicitly
   called each time the function is called.  For instance:

     f = &write("Hello\n");

   Assigns the write function to the variable f; it also freezes the
   value "Hello\n" as the first argument.
   Now, executing 
 
     f(); 
 
   is the same as executing 

     write("Hello.\n");

  
   It is possible to freeze only a few of the arguments to a function at
   one time.  For instance:

     function set_sk = &set_skill(SS_AWARENESS);

   freezes only the first argument of set_skill (it takes two arguments).
   So, using the above function, you can call

     set_sk(10);

   which would be the equivalent of calling 

     set_skill(SS_AWARENESS, 10);

   If you wanted to freeze the second arg, but not the first, the
   syntax would be

     set_sk = &set_skill(, 10);

   The comma before the 10 (the value to be frozen as the second argument)
   acts as a place-holder for the first argument.

   Using the above function variable to freeze the second argument, you can
   call set_skill in this manner:

     set_sk(SS_DEFENCE);

   which would be the same as 
    
     set_skill(SS_DEFENCE, 10);

5. Function composition

   Composition of two functions is possible using the @ operator.
   For instance:

     function f = &write() @ &lower_case()
     f("A");

   is equivalent to 

     write(lower_case("A"));

   In other words, the return value from each function, starting at
   the rightmost function, is passed as an argument to the function
   to the left.

6. Miscellanea

   1. It is possible to create a function variable so that the first
      argument passed to it will designate the object in which the
      function will be called.  The syntax is as follows:

        function f = &->function_name();

      Ex.

        object player = find_player("shiva");
        function f = &->query_name();
        f(player);

      The above is equivalent to the following:

        object player = find_player("shiva");
        player->query_name();

      Here is a more useful example:

        function f = &->query_invis();
        object *users_who_are_invis = filter(users(), f);    
    

   2. A shorthand for
       
        function f = &function_name();

      is 
 
        function f = function_name;

     
      For instance,

        function f = &write();

      is equivalent to

        function f = write;

   3. To assign a function to a function-type variable, it must have
      been declared previously, i.e. it must be previously prototyped
      or defined.

      For instance:

        void func1()
        {
          function f = func2();
        }
 
        int func2() { return 1; }

      will cause an error.  This can be fixed in two ways:

      1. Prototype

         int func2();

         void func1()
         {
           function f = func2();
         }
 
         void func2() { return 1; }

      2. Define the function before referencing it

         int func2() { return 1; }        

         void func1()
         {
           function f = func2();
         }

   4. operator

      operator is a very handy function to use with function-type
      variables:  it allows binary operations to be performed as
      functions and thus to be used in function-type variables.

      The syntax is

        operator(binary_operator)(arg1, arg2)

      For instance:

        function f = &operator(==);
        f(2, 1);

      would return 0 (2 is not equal to 1).

        function f = &operator(>)(0);
        f(-1);
  
      would return 1 (0 is greater than -1).

      operator is most useful as part of a composite function, though.
      For instance:

        function is_in_array = &operator(>)(, -1) @ &member_array(, arr);

      Now, is_in_array(val) will return 1 or 0 depending on whether val
      is in the array arr.

      Valid operators for the operator function are as follows:

        +, -, *, /, >, <, <=, >=, ==, !=, &&, ||, &, |, ^, [], <<, >>

      [] is a special case, where

        int *arr = ({ 1, 2, 3, 4 });
        function f = &operator([]);
        f(arr, 1);

      returns 2 (element 1 of the array arr).


7. Examples

   Here are a few examples of varying complexity and usefulness.
   ____________________________________________________________________
   This is an entirely self-contained add_action which clones an object
   and moves it to a living when the living executes the command "ugh":

   function f = &operator(==)(0) @ &->move(player, 1) @ clone_object;
   add_action(f, "ugh");
   ___________________________________________________________________
   This returns all people in the game with names starting with "sh":

   function f = &wildmatch("sh*") @ &->query_real_name();
   filter(users(), f);
   ___________________________________________________________________
   Delay a message to a player:

   function f = &player->catch_msg("Hiya!\n");
   set_alarm(1.0, 0.0, f);
   ___________________________________________________________________
   write out the names of all npcs with more than 10 gold coins:

   function is_gold_coin = &operator(==)("gold") @ &->query_coin_type();
   function more_than_ten = &operator(>)(, 10) @ &->num_heap();
   function env = environment;
   function is_npc = &->query_npc();

   object *envs;
   object *gold_coins = filter(object_clones(find_object("/std/coins")),
       is_gold_coin);
   
   gold_coins = filter(gold_coins, more_than_ten);
   envs = map(gold_coins, environment);
   envs = filter(envs, is_npc);
   dump_array(env->query_real_name());

   ...or for an even more convoluted version:

   dump_array(filter(map(filter(filter(object_clones(find_object(
       "/std/coins")), &operator(==)("gold") @ &->query_coin_type()),
       &operator(>)(, 10) @ &->num_heap()), environment),
       &->query_npc())->query_real_name());
