squiggle/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Danger.res

668 lines
24 KiB
Plaintext
Raw Normal View History

open FunctionRegistry_Core
open FunctionRegistry_Helpers
let nameSpace = "Danger"
let requiresNamespace = true
2022-09-05 10:38:15 +00:00
module NNumbersToNumber = {
module One = {
let make = (name, fn) =>
FnDefinition.make(
~name,
~inputs=[FRTypeNumber],
~run=(_, inputs, _, _) => {
inputs
->getOrError(0)
->E.R.bind(Prepare.oneNumber)
->E.R2.fmap(fn)
->E.R2.fmap(Wrappers.evNumber)
},
(),
)
}
2022-09-05 10:38:15 +00:00
module Two = {
let make = (name, fn) =>
FnDefinition.make(
~name,
~inputs=[FRTypeNumber, FRTypeNumber],
~run=(_, inputs, _, _) => {
inputs->Prepare.ToValueTuple.twoNumbers->E.R2.fmap(fn)->E.R2.fmap(Wrappers.evNumber)
},
(),
)
}
2022-09-05 10:38:15 +00:00
module Three = {
let make = (name, fn) =>
FnDefinition.make(
~name,
~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber],
~run=(_, inputs, _, _) => {
inputs->Prepare.ToValueTuple.threeNumbers->E.R2.fmap(fn)->E.R2.fmap(Wrappers.evNumber)
},
(),
)
}
}
module Internals = {
// Probability functions
let factorial = Stdlib.Math.factorial
let choose = ((n, k)) => factorial(n) /. (factorial(n -. k) *. factorial(k))
let pow = (base, exp) => Js.Math.pow_float(~base, ~exp)
let binomial = ((n, k, p)) => choose((n, k)) *. pow(p, k) *. pow(1.0 -. p, n -. k)
2022-09-05 10:38:15 +00:00
// Integral helper functions
2022-09-04 18:26:57 +00:00
let applyFunctionAtPoint = (
aLambda,
internalNumber: internalExpressionValue,
environment,
reducer,
): result<ReducerInterface_InternalExpressionValue.t, Reducer_ErrorValue.errorValue> => {
2022-09-05 10:38:15 +00:00
let result = Reducer_Expression_Lambda.doLambdaCall(
2022-09-05 07:39:55 +00:00
aLambda,
2022-09-05 10:38:15 +00:00
list{internalNumber},
2022-09-05 07:39:55 +00:00
environment,
reducer,
)
result
2022-09-04 18:07:10 +00:00
}
2022-09-05 10:38:15 +00:00
let castFloatToInternalNumber = x => ReducerInterface_InternalExpressionValue.IEvNumber(x)
let castArrayOfFloatsToInternalArrayOfInternals = xs => ReducerInterface_InternalExpressionValue.IEvArray(
Belt.Array.map(xs, x => castFloatToInternalNumber(x)),
)
@dead
let applyFunctionAtFloat = (aLambda, point, environment, reducer) =>
2022-09-05 10:38:15 +00:00
// reason for existence: might be an useful template to have for calculating diminishing marginal returns later on
applyFunctionAtPoint(aLambda, castFloatToInternalNumber(point), environment, reducer)
// integrate function itself
let integrateFunctionBetweenWithNumIntegrationPoints = (
aLambda,
min: float,
max: float,
2022-09-05 10:38:15 +00:00
numIntegrationPoints: float, // cast as int?
environment,
reducer,
) => {
let applyFunctionAtFloatToFloatOption = (point: float) => {
2022-09-05 10:38:15 +00:00
// Defined here so that it has access to environment, reducer
let pointAsInternalExpression = castFloatToInternalNumber(point)
let resultAsInternalExpression = Reducer_Expression_Lambda.doLambdaCall(
aLambda,
list{pointAsInternalExpression},
environment,
reducer,
)
let result = switch resultAsInternalExpression {
| Ok(IEvNumber(x)) => Ok(x)
2022-09-05 10:38:15 +00:00
| Error(_) =>
Error(
2022-09-05 10:49:47 +00:00
"Integration error 1 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead",
2022-09-05 10:38:15 +00:00
)
2022-09-05 10:49:47 +00:00
| _ => Error("Integration error 2 in Danger.integrate")
}
result
}
// worked example in comments below, assuming min=0, max = 10
2022-09-05 10:38:15 +00:00
let numTotalPoints = Belt.Float.toInt(numIntegrationPoints) // superflous declaration, but useful to keep track that we are interpreting "numIntegrationPoints" as the total number on which we evaluate the function, not e.g., as the inner integration points.
2022-09-05 10:16:19 +00:00
let numInnerPoints = numTotalPoints - 2
let numOuterPoints = 2
let totalWeight = max -. min
let weightForAnInnerPoint = totalWeight /. E.I.toFloat(numTotalPoints - 1)
let weightForAnOuterPoint = totalWeight /. E.I.toFloat(numTotalPoints - 1) /. 2.0
let innerPointIncrement = (max -. min) /. E.I.toFloat(numTotalPoints - 1)
let innerXs = Belt.Array.makeBy(numInnerPoints, i =>
min +. Belt_Float.fromInt(i + 1) *. innerPointIncrement
)
2022-09-05 10:38:15 +00:00
// Gotcha: makeBy goes from 0 to (n-1): <https://rescript-lang.org/docs/manual/latest/api/belt/array#makeby>
let ysOptions = Belt.Array.map(innerXs, x => applyFunctionAtFloatToFloatOption(x))
let okYs = E.A.R.filterOk(ysOptions)
2022-09-05 10:38:15 +00:00
/* Logging, with a worked example. */
// Useful for understanding what is happening.
// assuming min = 0, max = 10, numTotalPoints=10, results below:
let verbose = false
if verbose {
Js.Console.log2("numTotalPoints", numTotalPoints) // 5
Js.Console.log2("numInnerPoints", numInnerPoints) // 3
Js.Console.log2("numOuterPoints", numOuterPoints) // always 2
Js.Console.log2("totalWeight", totalWeight) // 10 - 0 = 10
Js.Console.log2("weightForAnInnerPoint", weightForAnInnerPoint) // 10/4 = 2.5
Js.Console.log2("weightForAnOuterPoint", weightForAnOuterPoint) // 10/4/2 = 1.25
Js.Console.log2(
"weightForAnInnerPoint * numInnerPoints + weightForAnOuterPoint * numOuterPoints",
weightForAnInnerPoint *. E.I.toFloat(numInnerPoints) +.
weightForAnOuterPoint *. E.I.toFloat(numOuterPoints),
) // should be 10
Js.Console.log2(
"sum of weights == totalWeight",
weightForAnInnerPoint *. E.I.toFloat(numInnerPoints) +.
weightForAnOuterPoint *. E.I.toFloat(numOuterPoints) == totalWeight,
) // true
Js.Console.log2("innerPointIncrement", innerPointIncrement) // (10-0)/4 = 2.5
Js.Console.log2("innerXs", innerXs) // 2.5, 5, 7.5
Js.Console.log2("ysOptions", ysOptions)
Js.Console.log2("okYs", okYs)
}
let result = switch E.A.length(ysOptions) == E.A.length(okYs) {
| true => {
let innerPointsSum = okYs->E.A.reduce(0.0, (a, b) => a +. b)
2022-09-05 10:16:19 +00:00
let resultWithOuterPoints = switch (
applyFunctionAtFloatToFloatOption(min),
applyFunctionAtFloatToFloatOption(max),
) {
| (Ok(yMin), Ok(yMax)) => {
let result =
(yMin +. yMax) *. weightForAnOuterPoint +. innerPointsSum *. weightForAnInnerPoint
let wrappedResult = result->ReducerInterface_InternalExpressionValue.IEvNumber->Ok
wrappedResult
}
| (Error(b), _) => Error(b)
| (_, Error(b)) => Error(b)
}
resultWithOuterPoints
}
| false =>
Error(
"Integration error 3 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead",
)
}
result
}
type diminishingReturnsAccumulatorInner = {
optimalAllocations: array<float>,
2022-09-05 13:51:55 +00:00
currentMarginalReturns: result<array<float>, string>,
}
let findBiggestElementIndex = xs =>
E.A.reducei(xs, 0, (acc, newElement, index) => {
switch newElement > xs[acc] {
| true => index
| false => acc
}
})
type diminishingReturnsAccumulator = result<diminishingReturnsAccumulatorInner, string>
let diminishingMarginalReturnsForTwoFunctions = (
lambda1,
lambda2,
funds,
approximateIncrement,
environment,
reducer,
) => {
/*
Two possible algorithms (n=funds/increment, m=num lambdas)
1. O(n): Iterate through value on next n dollars. At each step, only compute the new marginal return of the function which is spent
2. O(n*m): Iterate through all possible spending combinations. Fun is, it doesn't assume that the returns of marginal spending are diminishing.
*/
let applyFunctionAtFloatToFloatOption = (lambda, point: float) => {
// Defined here so that it has access to environment, reducer
let pointAsInternalExpression = castFloatToInternalNumber(point)
let resultAsInternalExpression = Reducer_Expression_Lambda.doLambdaCall(
lambda,
list{pointAsInternalExpression},
environment,
reducer,
)
let result = switch resultAsInternalExpression {
| Ok(IEvNumber(x)) => Ok(x)
| Error(_) =>
Error(
"Integration error 1 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead",
)
| _ => Error("Integration error 2 in Danger.integrate")
}
result
}
let numDivisions = Js.Math.round(funds /. approximateIncrement)
let numDivisionsInt = Belt.Float.toInt(numDivisions)
let increment = funds /. numDivisions
let arrayOfIncrements = Belt.Array.makeBy(numDivisionsInt, _ => increment)
let initAccumulator: diminishingReturnsAccumulator = Ok({
optimalAllocations: [0.0, 0.0],
2022-09-05 13:51:55 +00:00
currentMarginalReturns: E.A.R.firstErrorOrOpen([
applyFunctionAtFloatToFloatOption(lambda1, 0.0),
applyFunctionAtFloatToFloatOption(lambda2, 0.0),
2022-09-05 13:51:55 +00:00
]),
})
let optimalAllocationEndAccumulator = E.A.reduce(arrayOfIncrements, initAccumulator, (
acc,
2022-09-05 13:51:55 +00:00
newIncrement,
) => {
2022-09-05 14:08:06 +00:00
switch acc {
| Ok(accInner) => {
let oldMarginalReturnsWrapped = accInner.currentMarginalReturns
2022-09-05 14:08:06 +00:00
let newAccWrapped = switch oldMarginalReturnsWrapped {
| Ok(oldMarginalReturns) => {
let indexOfBiggestDMR = findBiggestElementIndex(oldMarginalReturns)
2022-09-05 14:08:06 +00:00
let newOptimalAllocations = Belt.Array.copy(accInner.optimalAllocations)
let newOptimalAllocationsi = newOptimalAllocations[indexOfBiggestDMR] +. newIncrement
newOptimalAllocations[indexOfBiggestDMR] = newOptimalAllocationsi
2022-09-05 14:08:06 +00:00
let lambdai = indexOfBiggestDMR == 0 ? lambda1 : lambda2 // to do: generalize
let newMarginalResultsLambdai = applyFunctionAtFloatToFloatOption(
lambdai,
newOptimalAllocationsi,
)
let newCurrentMarginalReturns = switch newMarginalResultsLambdai {
| Ok(value) => {
let result = Belt.Array.copy(oldMarginalReturns)
result[indexOfBiggestDMR] = value
Ok(result)
2022-09-05 13:51:55 +00:00
}
2022-09-05 14:08:06 +00:00
| Error(b) => Error(b)
2022-09-05 13:51:55 +00:00
}
2022-09-05 14:08:06 +00:00
2022-09-05 13:51:55 +00:00
let newAcc: diminishingReturnsAccumulatorInner = {
optimalAllocations: newOptimalAllocations,
2022-09-05 14:08:06 +00:00
currentMarginalReturns: newCurrentMarginalReturns,
2022-09-05 13:51:55 +00:00
}
Ok(newAcc)
}
2022-09-05 14:08:06 +00:00
| Error(b) => Error(b)
2022-09-05 13:51:55 +00:00
}
newAccWrapped
}
2022-09-05 14:08:06 +00:00
| Error(b) => Error(b)
2022-09-05 13:51:55 +00:00
}
2022-09-05 14:08:06 +00:00
/* let findSmaller = (_) => 0
2022-09-05 13:51:55 +00:00
let smallerDMR =
acc
2022-09-05 14:08:06 +00:00
*/
})
let optimalAllocationResult = switch optimalAllocationEndAccumulator {
| Ok(inner) => Ok(castArrayOfFloatsToInternalArrayOfInternals(inner.optimalAllocations))
| Error(b) => Error(b)
}
optimalAllocationResult
}
let diminishingMarginalReturnsForManyFunctions = (
2022-09-05 18:52:23 +00:00
lambdas,
funds,
approximateIncrement,
environment,
reducer,
) => {
/*
Two possible algorithms (n=funds/increment, m=num lambdas)
1. O(n): Iterate through value on next n dollars. At each step, only compute the new marginal return of the function which is spent
2. O(n*m): Iterate through all possible spending combinations. Fun is, it doesn't assume that the returns of marginal spending are diminishing.
*/
2022-09-05 18:52:23 +00:00
let applyFunctionAtFloatToFloatOption = (lambda, point: float) => {
// Defined here so that it has access to environment, reducer
let pointAsInternalExpression = castFloatToInternalNumber(point)
let resultAsInternalExpression = Reducer_Expression_Lambda.doLambdaCall(
lambda,
list{pointAsInternalExpression},
environment,
reducer,
)
let result = switch resultAsInternalExpression {
| Ok(IEvNumber(x)) => Ok(x)
| Error(_) =>
Error(
"Integration error 1 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead",
)
| _ => Error("Integration error 2 in Danger.integrate")
}
result
}
2022-09-05 18:52:23 +00:00
/*
let numDivisions = Js.Math.round(funds /. approximateIncrement)
let numDivisionsInt = Belt.Float.toInt(numDivisions)
let increment = funds /. numDivisions
let arrayOfIncrements = Belt.Array.makeBy(numDivisionsInt, _ => increment)
let numLambdas = E.A.length(lambdas)
let initAccumulator: diminishingReturnsAccumulator = Ok({
optimalAllocations: Belt.Array.makeBy(numLambdas, _ => 0.0),
currentMarginalReturns: E.A.fmap(
lambda => applyFunctionAtFloatToFloatOption(lambda, 0.0),
lambdas,
)->E.A.R.firstErrorOrOpen,
})
let optimalAllocationEndAccumulator = E.A.reduce(arrayOfIncrements, initAccumulator, (
acc,
newIncrement,
) => {
switch acc {
| Ok(accInner) => {
let oldMarginalReturnsWrapped = accInner.currentMarginalReturns
let newAccWrapped = switch oldMarginalReturnsWrapped {
| Ok(oldMarginalReturns) => {
let indexOfBiggestDMR = findBiggestElementIndex(oldMarginalReturns)
let newOptimalAllocations = Belt.Array.copy(accInner.optimalAllocations)
let newOptimalAllocationsi =
newOptimalAllocations[indexOfBiggestDMR] +. newIncrement
newOptimalAllocations[indexOfBiggestDMR] = newOptimalAllocationsi
let lambdai = lambdas[indexOfBiggestDMR]
let newMarginalResultsLambdai = applyFunctionAtFloatToFloatOption(
lambdai,
newOptimalAllocationsi,
)
let newCurrentMarginalReturns = switch newMarginalResultsLambdai {
| Ok(value) => {
let result = Belt.Array.copy(oldMarginalReturns)
result[indexOfBiggestDMR] = value
Ok(result)
}
| Error(b) => Error(b)
}
let newAcc: diminishingReturnsAccumulatorInner = {
optimalAllocations: newOptimalAllocations,
currentMarginalReturns: newCurrentMarginalReturns,
}
Ok(newAcc)
}
| Error(b) => Error(b)
}
newAccWrapped
}
| Error(b) => Error(b)
}
})
let optimalAllocationResult = switch optimalAllocationEndAccumulator {
| Ok(inner) => Ok(castArrayOfFloatsToInternalArrayOfInternals(inner.optimalAllocations))
| Error(b) => Error(b)
}
2022-09-05 18:52:23 +00:00
// optimalAllocationResult
*/
let result = [0.0, 0.0]->castArrayOfFloatsToInternalArrayOfInternals->Ok
result
}
}
let library = [
Function.make(
~name="laplace",
~nameSpace,
~requiresNamespace,
~output=EvtNumber,
~examples=[`Danger.laplace(1, 20)`],
~definitions=[
2022-09-05 10:38:15 +00:00
NNumbersToNumber.Two.make("laplace", ((successes, trials)) =>
(successes +. 1.0) /. (trials +. 2.0)
),
],
(),
),
Function.make(
~name="factorial",
~nameSpace,
~requiresNamespace,
~output=EvtNumber,
~examples=[`Danger.factorial(20)`],
2022-09-05 10:38:15 +00:00
~definitions=[NNumbersToNumber.One.make("factorial", Internals.factorial)],
(),
),
Function.make(
~name="choose",
~nameSpace,
~requiresNamespace,
~output=EvtNumber,
~examples=[`Danger.choose(1, 20)`],
2022-09-05 10:38:15 +00:00
~definitions=[NNumbersToNumber.Two.make("choose", Internals.choose)],
(),
),
Function.make(
~name="binomial",
~nameSpace,
~requiresNamespace,
~output=EvtNumber,
~examples=[`Danger.binomial(1, 20, 0.5)`],
2022-09-05 10:38:15 +00:00
~definitions=[NNumbersToNumber.Three.make("binomial", Internals.binomial)],
(),
),
// Helper functions building up to the integral
Function.make(
~name="applyFunctionAtZero",
~nameSpace,
~output=EvtNumber,
~requiresNamespace=false,
~examples=[`Danger.applyFunctionAtZero({|x| x+1})`],
~definitions=[
FnDefinition.make(
2022-09-04 18:07:10 +00:00
~name="applyFunctionAtZero",
~inputs=[FRTypeLambda],
2022-09-05 10:38:15 +00:00
~run=(inputs, _, environment, reducer) => {
let result = switch inputs {
| [IEvLambda(aLambda)] =>
2022-09-05 10:38:15 +00:00
Internals.applyFunctionAtPoint(
aLambda,
Internals.castFloatToInternalNumber(0.0),
environment,
reducer,
)->E.R2.errMap(_ => "Error!")
| _ => Error(impossibleError)
}
result
},
(),
),
],
(),
),
Function.make(
~name="applyFunctionAtPoint",
~nameSpace,
~output=EvtNumber,
~requiresNamespace=false,
~examples=[`Danger.applyFunctionAtPoint({|x| x+1}, 1)`],
~definitions=[
FnDefinition.make(
~name="applyFunctionAtPoint",
~inputs=[FRTypeLambda, FRTypeNumber],
~run=(inputs, _, env, reducer) =>
switch inputs {
| [IEvLambda(aLambda), point] =>
Internals.applyFunctionAtPoint(aLambda, point, env, reducer)->E.R2.errMap(_ => "Error!")
| _ => Error(impossibleError)
},
(),
),
],
(),
),
2022-09-05 10:38:15 +00:00
// Integral in terms of function, min, max, num points
// Note that execution time will be more predictable, because it
// will only depend on num points and the complexity of the function
Function.make(
2022-09-05 10:38:15 +00:00
~name="integrateFunctionBetweenWithNumIntegrationPoints",
~nameSpace,
~output=EvtNumber,
~requiresNamespace=false,
2022-09-05 10:38:15 +00:00
~examples=[`Danger.integrateFunctionBetweenWithNumIntegrationPoints({|x| x+1}, 1, 10, 10)`],
2022-09-05 06:41:33 +00:00
// should be [x^2/2 + x]1_10 = (100/2 + 10) - (1/2 + 1) = 60 - 1.5 = 58.5
// https://www.wolframalpha.com/input?i=integrate+x%2B1+from+1+to+10
~definitions=[
FnDefinition.make(
2022-09-05 10:38:15 +00:00
~name="integrateFunctionBetweenWithNumIntegrationPoints",
~inputs=[FRTypeLambda, FRTypeNumber, FRTypeNumber, FRTypeNumber],
~run=(inputs, _, env, reducer) => {
let result = switch inputs {
| [_, _, _, IEvNumber(0.0)] =>
2022-09-05 10:49:47 +00:00
Error("Integration error 4 in Danger.integrate: Increment can't be 0.")
2022-09-05 10:38:15 +00:00
| [IEvLambda(aLambda), IEvNumber(min), IEvNumber(max), IEvNumber(numIntegrationPoints)] =>
Internals.integrateFunctionBetweenWithNumIntegrationPoints(
aLambda,
min,
max,
2022-09-05 10:38:15 +00:00
numIntegrationPoints,
env,
reducer,
)
| _ =>
Error(
"Integration error 5 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))",
)
}
result
},
(),
),
],
(),
),
2022-09-05 10:38:15 +00:00
// Integral in terms of function, min, max, epsilon (distance between points)
// Note that execution time will be less predictable, because it
// will depend on min, max and epsilon together,
// as well and the complexity of the function
2022-09-05 07:39:55 +00:00
Function.make(
2022-09-05 10:38:15 +00:00
~name="integrateFunctionBetweenWithEpsilon",
~nameSpace,
~output=EvtNumber,
~requiresNamespace=false,
2022-09-05 11:09:28 +00:00
~examples=[`Danger.integrateFunctionBetweenWithEpsilon({|x| x+1}, 1, 10, 0.1)`],
~definitions=[
FnDefinition.make(
2022-09-05 10:38:15 +00:00
~name="integrateFunctionBetweenWithEpsilon",
~inputs=[FRTypeLambda, FRTypeNumber, FRTypeNumber, FRTypeNumber],
~run=(inputs, _, env, reducer) => {
let result = switch inputs {
| [_, _, _, IEvNumber(0.0)] =>
Error("Integration error in Danger.integrate: Increment can't be 0.")
2022-09-05 10:38:15 +00:00
| [IEvLambda(aLambda), IEvNumber(min), IEvNumber(max), IEvNumber(epsilon)] =>
Internals.integrateFunctionBetweenWithNumIntegrationPoints(
aLambda,
min,
max,
2022-09-05 10:38:15 +00:00
(max -. min) /. epsilon,
2022-09-05 07:39:55 +00:00
env,
reducer,
)->E.R2.errMap(_ =>
2022-09-05 10:49:47 +00:00
"Integration error 7 in Danger.integrate. Something went wrong along the way"
)
| _ =>
Error(
2022-09-05 10:49:47 +00:00
"Integration error 8 in Danger.integrate. Remember that inputs are (function, number (min), number (max), number(increment))",
)
}
result
},
(),
),
],
(),
),
Function.make(
~name="diminishingMarginalReturnsForTwoFunctions",
~nameSpace,
~output=EvtArray,
~requiresNamespace=false,
~examples=[`Danger.diminishingMarginalReturnsForTwoFunctions({|x| x+1}, {|y| 10}, 100, 0.01)`],
~definitions=[
FnDefinition.make(
~name="diminishingMarginalReturnsForTwoFunctions",
~inputs=[FRTypeLambda, FRTypeLambda, FRTypeNumber, FRTypeNumber],
~run=(inputs, _, env, reducer) =>
switch inputs {
| [
IEvLambda(lambda1),
IEvLambda(lambda2),
IEvNumber(funds),
IEvNumber(approximateIncrement),
] =>
Internals.diminishingMarginalReturnsForTwoFunctions(
lambda1,
lambda2,
funds,
approximateIncrement,
env,
reducer,
)
| _ => Error("Error in Danger.diminishingMarginalReturnsForTwoFunctions")
},
(),
),
],
(),
),
Function.make(
~name="diminishingMarginalReturnsForManyFunctions",
~nameSpace,
~output=EvtArray,
~requiresNamespace=false,
~examples=[
2022-09-05 18:52:23 +00:00
`Danger.diminishingMarginalReturnsForManyFunctions([{|x| x+1}, {|y| 10}], 100, 0.01)`,
],
~definitions=[
FnDefinition.make(
~name="diminishingMarginalReturnsForManyFunctions",
~inputs=[FRTypeArray(FRTypeLambda), FRTypeNumber, FRTypeNumber],
~run=(inputs, _, environment, reducer) =>
switch inputs {
| [IEvArray(innerlambdas), IEvNumber(funds), IEvNumber(approximateIncrement)] => {
/*let individuallyWrappedLambdas = E.A.fmap(innerLambda => {
switch innerLambda {
| ReducerInterface_InternalExpressionValue.IEvLambda(lambda) => Ok(lambda)
| _ =>
Error(
"Error in Danger.diminishingMarginalReturnsForManyFunctions. A member of the array wasn't a function",
)
}
}, innerlambdas)
let wrappedLambdas = E.A.R.firstErrorOrOpen(individuallyWrappedLambdas)
let result = switch wrappedLambdas {
| Ok(lambdas) => {
let result = Internals.diminishingMarginalReturnsForManyFunctions(
lambdas,
funds,
approximateIncrement,
environment,
reducer,
)
result
}
| Error(b) => Error(b)
}
result
*/
Error("wtf man")
}
| _ => Error("Error in Danger.diminishingMarginalReturnsForTwoFunctions")
},
(),
),
],
(),
),
/*
Function.make(
~name="diminishingMarginalReturnsForManyFunctions",
~nameSpace,
~output=EvtArray,
~requiresNamespace=false,
~examples=[
`Danger.diminishingMarginalReturnsForManyFunctions([{|x| x+1}, {|y| 10}, {|z| 20 - 2*z}], 100, 0.01)`,
],
~definitions=[
FnDefinition.make(
~name="diminishingMarginalReturnsForManyFunctions",
~inputs=[FRTypeArray(FRTypeLambda), FRTypeNumber, FRTypeNumber],
~run=(inputs, _, env, reducer) =>
switch inputs {
2022-09-05 18:52:23 +00:00
| [IEvArray(innerlambdas), IEvNumber(funds), IEvNumber(approximateIncrement)] => {
let result = [0.0, 0.0]->Internals.castArrayOfFloatsToInternalArrayOfInternals->Ok
result
}
/*
Internals.diminishingMarginalReturnsForManyFunctions(
innerlambdas,
funds,
approximateIncrement,
env,
reducer,
2022-09-05 18:52:23 +00:00
)*/
| _ => Error("Error in Danger.diminishingMarginalReturnsForManyFunctions")
},
(),
),
],
(),
2022-09-05 18:52:23 +00:00
),*/
]