a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
f56aef1999-09-06Fredrik Hübinette (Hubbe) constant defined = __builtin.function_defined;
f321a82000-11-21Johan Sundström 
e5ef062003-04-01Martin Nilsson //! Calls the given function with the @[args] array plus the optional
f321a82000-11-21Johan Sundström //! extra arguments as its arguments and returns the result. //!
e5ef062003-04-01Martin Nilsson //! Most useful in conjunction with @[map], and particularly in combination //! with @[sscanf] with @expr{"...%{...%}..."@} scan strings (which indeed
f321a82000-11-21Johan Sundström //! was what it was invented for in the first place). //!
c00a382001-05-10Henrik Grubbström (Grubba) //! @param args
e5ef062003-04-01Martin Nilsson //! The first arguments the function @[f] expects.
c00a382001-05-10Henrik Grubbström (Grubba) //! @param f
e5ef062003-04-01Martin Nilsson //! The function to apply the arguments on.
c00a382001-05-10Henrik Grubbström (Grubba) //! @param extra
e5ef062003-04-01Martin Nilsson //! Optional extra arguments to send to @[f].
c00a382001-05-10Henrik Grubbström (Grubba) //! @returns
e5ef062003-04-01Martin Nilsson //! Whatever the supplied function @[f] returns.
c00a382001-05-10Henrik Grubbström (Grubba) //!
f321a82000-11-21Johan Sundström //! @example
1952d82003-04-04Martin Nilsson //! @code
f321a82000-11-21Johan Sundström //! class Product(string name, string version) //! { //! string _sprintf() //! { //! return sprintf("Product(%s/%s)", name, version); //! } //! } //! map(({ ({ "pike", "7.1.11" }), //! ({ "whitefish", "0.1" }) }), //! Function.splice_call, Product); //! ({ /* 2 elements */ //! Product(pike/7.1.11), //! Product(whitefish/0.1) //! })
1952d82003-04-04Martin Nilsson //! @endcode
f321a82000-11-21Johan Sundström mixed splice_call(array args, function f, mixed|void ... extra) { return f(@args, @extra); }
7424d62003-11-20Marcus Comstedt  //! The dreaded fixpoint combinator "Y". //! //! The Y combinator is useful when writing recursive lambdas. It //! converts a lambda that expects a self-reference as its first argument //! into one which can be called without this argument. //! //! @example //! This example creates a lambda that computes the faculty function. //! @code //! Function.Y(lambda(function f, int n) { return n>1? n*f(n-1) : 1; }) //! @endcode function Y(function f) { return lambda(function p) { return lambda(mixed ... args) { return f(p(p), @args); }; } (lambda(function p) { return lambda(mixed ... args) { return f(p(p), @args); }; }); } //! Partially evaluate a function call. //! //! This function allows N parameters to be given to a function taking //! M parameters (N<=M), yielding a new function taking M-N parameters. //! //! What is actually returned from this function is a function taking N //! parameters, and returning a function taking M-N parameters. //! //! @example //! This example creates a function adding 7 to its argument. //! @code //! Function.curry(`+)(7) //! @endcode
a3a9bc2013-04-16Per Hedbor function(mixed...:function(mixed...:mixed|void)) curry(function f)
7424d62003-11-20Marcus Comstedt { return lambda(mixed ... args1) { return lambda(mixed ... args2) { return f(@args1, @args2); }; }; }
24e8d32003-12-08Mirar (Pontus Hagland) 
e89cc82016-05-30Per Hedbor //! Partially evaluate a function call. //! //! This function returns a function that when called will do the //! specified argument mapping. It is similar to @[curry], but allows //! more dynamic changes of the argument evaluation, you can leave the //! first argument unspecified while setting others, or simply change //! the argument order. //! //! The first argument is the function to be called. //! //! All other arguments is either a generic value, which will be sent as-is to the funciton //! or one of the placeholder values define in [Function.Placeholder], //! or one of your own implementation (inherit //! Function.Placeholder.Base and implement the value function.). //! //! @example //! This example returns a funciton that limits the given argument //! to between 0 and 99. //! @code //! import Functio.Placeholder; //! function clip = Function.bind(limit, 0, arg0, 100); //! @endcode class bind(function f, mixed ... bind_args) { protected string _sprintf() { return sprintf("Function.bind(%O%{, %O%})",f,bind_args); } protected mixed `()(mixed ... args) { array processed = ({}); for(int i=0; i<sizeof(bind_args);i++) { if( objectp(bind_args[i]) && bind_args[i]->_is_placeholder ) { mixed val = bind_args[i]->value(this,args); if( bind_args[i]->_splice ) processed += val; else processed += ({val}); } else processed += ({bind_args[i]}); } return f(@processed); } }
24e8d32003-12-08Mirar (Pontus Hagland) 
3a34b12014-09-03Per Hedbor //! This function, given a function taking N parameters, returns a new //! function taking N+1 parameters. The first argument will be //! ignored. //! //! @example //! @code //! > Function.uncurry(`+)(7,2,3) //! Result: 5 //! @endcode
7751d92014-09-03Per Hedbor function(mixed...:mixed) uncurry(function f)
3a34b12014-09-03Per Hedbor { return lambda(mixed ... args1) { return f(@args1[1..]); }; }
24e8d32003-12-08Mirar (Pontus Hagland) //! Call a callback function, but send throws from the callback //! function (ie, errors) to master()->handle_error. //! Also accepts if f is zero (0) without error. //! //! @example //! @code
3a34b12014-09-03Per Hedbor //! Functions.call_callback(the_callback,some,arguments);
24e8d32003-12-08Mirar (Pontus Hagland) //! @endcode
3524712015-05-26Martin Nilsson //! equals
24e8d32003-12-08Mirar (Pontus Hagland) //! @code //! { //! mixed err=catch { if (the_callback) the_callback(some,arguments); }; //! if (err) master()->handle_error(err); //! } //! @endcode //! (Approximately, since call_callback also calls handle_error //! if 0 were thrown.) void call_callback(function f,mixed ... args) { if (!f) return; mixed err=catch { f(@args); return; };
eede5e2004-02-23Martin Nilsson  handle_error(err);
24e8d32003-12-08Mirar (Pontus Hagland) }
eede5e2004-02-23Martin Nilsson 
3a34b12014-09-03Per Hedbor private function handle_error = master()->handle_error;
e6a17f2016-04-27Martin Nilsson  //! Creates a composite function of the provided functions. The //! composition function of f() and g(), q(x)=f(g(x)), is created by //! @expr{function q = Function.composite(f, g);@}. //! //! @example //! @code //! map(input/",", //! Function.composite(String.trim_all_whites, upper_case)); //! @endcode function composite(function ... f) { return lambda(mixed args) { for(int i; i<sizeof(f); i++) args = f[-i-1](args); return args; }; }
e89cc82016-05-30Per Hedbor  //! @module Placeholder //! //! Placeholder arguments for Function.bind object Placeholder = class { class Base { constant _is_placeholder = true; //! @decl mixed value(bind x, array args); //! //! The function that is called to return the argument value. } class Arg(int num) //! Arg(x) returns the value of argument X { inherit Base; protected string _sprintf() { return sprintf("arg%d",num); } mixed value(bind x, array args) { if(num>=sizeof(args) || -num>sizeof(args)) error("No argument %d given\n",num); return args[num]; } }; class Splice(int from, void|int end) //! Splice(from) adds all arguments starting with argument number @[from], //! optionally ending with end. //! Equivalent to @args[from..end] { inherit Base; constant _splice = true; array(mixed) value(bind x, array args) { if( end ) return args[from..end]; return args[from..]; } } //! @decl Arg rest; //! Return all arguments not used by any @[Arg] or @[Splice]. //! //! Unlike @[Splice] this will return non-continous unused arguments. //! //! @example //! This creates a version of call_out that has the function argument as //! the last argument //! @code //! import Function.Placeholder; //! Function.bind( call_out, Arg(-1), rest) //! @endcode object rest = class { inherit Base; constant _splice = true; array(mixed) value( bind x, array args ) { array ret = copy_value(args); foreach(x->bind_args, mixed arg) { if( Program.inherits(arg,Arg) ) { int a = arg->num; ret[a] = UNDEFINED; } else if( Program.inherits(arg,Splice) ) { int e = min(arg->end+1,sizeof(args)); if( e==1 ) e = sizeof(args); for(int i=arg->start; i<e; i++) ret[i] = UNDEFINED; } } return ret - ({ UNDEFINED }); } }(); //! @decl constant arg0; //! @decl constant arg1; //! @decl constant arg2; //! @decl constant arg3; //! @decl constant arg4; //! @decl constant arg5; //! @decl constant arg6; //! @decl constant arg7; //! @decl constant arg8; //! @decl constant arg9; //! @decl constant arg...; //! arg<n> will return an instance of @[Arg] that returns the n:th arg. //! For convenience for c++11 developers _0, _1 etc also works. //! //! Note that arg0 is the first argument, not arg1
15d35a2016-05-31Per Hedbor  class Expr(function func, void|bool _splice)
e89cc82016-05-30Per Hedbor  //! Expr(x) returns the result of calling @[x].
15d35a2016-05-31Per Hedbor  //! The function will be passed the list of arguments. //! //! If _splice is true, zero or more argument is returned in an array
e89cc82016-05-30Per Hedbor  //! //! Function.Placeholder.arg1 is thus more or less equivalent to
15d35a2016-05-31Per Hedbor  //! @code Expr(lambda(array args){return args[1];});
e89cc82016-05-30Per Hedbor  { inherit Base; protected string _sprintf() { return sprintf("Expr(%O)",value); }
15d35a2016-05-31Per Hedbor  mixed value( bind x, array args ) { return func(args); }
e89cc82016-05-30Per Hedbor  } private mapping _cache = ([]); mixed `[](string name) { if( _cache[name] ) return _cache[name]; mixed tmp; if(sscanf(name, "arg%d", tmp) || sscanf(name, "_%d", tmp)) return _cache[name] = Arg(tmp); return ::`[](name); }; }();