Partial Application

Partial application fixes part or all of the parameters of a function to generate a new function with fewer parameters.

Syntax

<functionName>{parameters}

or

Using object methods:

  • obj fixed as the first argument of method: obj.method{parameters...}(newArgs...) (equivalent to method{obj, parameters...}(newArgs...))

  • obj passed as the first argument to method:obj.{method{parameters...}}(newArgs...)(equivalent to method{parameters...}(obj, newArgs...))

Details

For positional parameters,

  • If you only want to fix the first few parameters, the remaining parameters are not required to be indicated.

  • If there are any unfixed parameters before a fixed one, their positions must be indicated.

For keyword parameters, you can only specify the parameters to be fixed.

When generating partial applications, you can use the constant DFLT to fix the parameters to their default values. It is important to note that when fixing optional parameters with an empty default value, DFLT should be used instead of NULL. For optional parameters with a default value that is not empty, you can use its default value or DFLT.

Partial application can be used with template functions that have certain requirements about function inputs.

Examples

a=100
g=add{a*a};
g(8)
// output: 10008
add{a*a}(88);
// output: 10088
def f(a,b):a*exp(b)
g=f{10};  // g(b)==f(10,b)
g(0);
// output: 10
g(1);
// output: 27.182818
k=f{,1};  // k(a)==f(a,1)
k(10);
// output: 27.182818

If there is a free optional parameter before a fixed parameter, and its position is not indicated, it must be specified when the partially applied function is called.

//Calculate the singular value decomposition of matrix m.
m=matrix([[2,1,0],[1,3,1],[0,1,4],[1,2,3]]);
// The syntax of function svd is svd(obj, [fullMatrices=true], [computeUV=true]). Since f1 does not have the optional *fullMatrices* parameter fixed, you must specify *fullMatrices* when executing f1, otherwise an error will be reported.
f1 = svd{m, computeUV=true}
f1(false)   // Successfully executed.
f1()  // An error is reported: The function [svd] expects 1 argument(s), but the actual number of arguments is: 0
Examples for using object methods to implement partial application for user-defined function myFunc.
//user-defined function myFunc
def myFunc(a,b,c){
    return a*10+b*5+c*2
}

a1=[1,2,3]
b1=5
c1=9

//fix the first parameter as a1
a1.myFunc{}(c1,b1)  //equivalent to myFunc{a1}(c1,b1)
// output: [65,75,85]
//fix the first and third parameters as b1 and a1
b1.myFunc{,a1}(c1)  //equivalent to myFunc{b1,,a1} (c1)
// output: [97,99,101]
//generate a partial application with only one parameter, myFunc{b1,a1}(c1)
b1.{myFunc{,a1}}(c1)    // equivalent to myFunc(b1,a1,c1)
// output: [73,78,83]

Partial application implemented by object methods can be used with higher-order function symbols.

  • Used with :E.

    a1.myFunc{b1}:E([4,5,6]) //equivalent to each(a1.myFunc{b1},[4,5,6])

    Returns a matrix:

    4 5 6
    43 45 47
    53 55 57
    63 65 67
  • Used with :V to calculate the skewness by column.

    av = array(INT[],0,10).append!([2 6 6 9 3, 0 7 4 7 1, 4 2 4 8 7,0 9 8 9 7])
    av.{skew{,false}}:V()// equivalent to skew{,false}:V(av) or byColumn(skew{,false},av)
    // output: [0.8545,-0.9406,0.8545,-0.8545,-0.3703]

    In this case, if you do not use "{}" to bind method and parameters, obj will be interpreted as the first fixed argument of skew. Since the skew function can only take two arguments, the following script will throw an exception:

    av.skew{,false}:H() // equivalent to skew{av,,false}:H()
    // throw an exception

The syntax of built-in function rank is rank(X, [ascending=true], [groupNum], [ignoreNA=true], [tiesMethod='min'], [percent=false], [precision].

To fix percent=true, use positional arguments:

f1 = rank{,,,,,true}

Alternatively, use keyword arguments:

f2 = rank{percent=true}

To fix groupNum to its default value (NULL), specify DFLT:

f3 = rank{groupNum=DFLT,percent=true}