Unlike your partial code, the code below will return a function with multiple parameters rather than a single parameter of type list. Perhaps you would like to add it to your module.
shared
Record.RemoveFirstN = (record as record,numToRemove as number) =>
let
FieldNames = Record.FieldNames(record),
RemoveFieldNames = List.FirstN(FieldNames,numToRemove)
in
Record.RemoveFields(record,RemoveFieldNames);
shared
_.Partial =
(f as function, a as list) =>
let
GetMinNumberOfArgs = (numArgs as number, numRequired as number, numFixed as number) as number =>
let
NumRemaining = numArgs - numFixed,
MinArgs = if numArgs=numRequired then NumRemaining else
if numRequired < numFixed then 0
else
numRequired - numFixed
in
MinArgs,
GetPartialSignature = (functionType as type,numFixed as number,parameters as record) =>
let
ReturnType = Type.FunctionReturn(functionType),
RemainingParameters = Record.RemoveFirstN(parameters,numFixed)
in
[ReturnType = ReturnType,Parameters = RemainingParameters],
CreatePartialFunction = (newFunctionType as type,fixed as list) =>
let
ToExecute = (remaining as list) => Function.Invoke(f, fixed & remaining),
Partial = Function.From(newFunctionType,ToExecute)
in
Partial,
NumFixed = List.Count(a),
FunctionType = Value.Type(f),
NumRequiredParameters = Type.FunctionRequiredParameters(FunctionType),
Parameters = Type.FunctionParameters(FunctionType),
MinNumberOrArgs = GetMinNumberOfArgs(Record.FieldCount(Parameters),NumRequiredParameters, NumFixed),
NewFunctionType = Type.ForFunction(GetPartialSignature(FunctionType,NumFixed,Parameters),MinNumberOrArgs),
PartialFunction = CreatePartialFunction(NewFunctionType,a)
in
PartialFunction;
shared MyExtension.UnitTest =
[
TestFn = (a as number, b as number, optional opt as number) =>
let
NotOptional = if opt <> null then opt else 0,
Result = a + b + NotOptional
in
Result,
PartialTest1 = _.Partial(TestFn,{9}),
PartialTest2 = _.Partial(TestFn,{9,1}),
facts =
{
Fact("Partial fixed 1 parameter - execute don't provide optional",
10,
PartialTest1(1)
),
Fact("Partial fixed 1 parameter - execute provide optional",
12,
PartialTest1(1,2)
),
Fact("Partial fixed 2 parameters - execute provide optional",
13,
PartialTest2(3)
),
Fact("Partial fixed 2 parameters - execute don't provide optional",
10,
PartialTest2()
),
Fact("Should throw when don't provide required",
"1 arguments were passed to function which expects between 2 and 3.",
let
Errored = try
PartialTest1()
in
Errored[Error][Message]
),
Fact("Should throw when provide incorrect parameter type",
"We cannot convert the value ""incorrect type"" to type Number.",
let
Errored = try
PartialTest1("incorrect type")
in
Errored[Error][Message]
),
Fact("Record.RemoveFirstN 1",
[Second="Second",Third="Third"],
Record.RemoveFirstN([First="First",Second="Second",Third="Third"],1)
),
Fact("Record.RemoveFirstN 2",
[Third="Third"],
Record.RemoveFirstN([First="First",Second="Second",Third="Third"],2)
)
},
report = Facts.Summarize(facts)
][report];