open FunctionRegistry_Core let impossibleError = "Wrong inputs / Logically impossible" module Wrappers = { let symbolic = r => DistributionTypes.Symbolic(r) let evDistribution = r => ReducerInterface_ExpressionValue.EvDistribution(r) let symbolicEvDistribution = r => r->Symbolic->evDistribution } module Prepare = { let recordWithTwoArgsToValues = (inputs: array): result, string> => switch inputs { | [Record([(_, n1), (_, n2)])] => Ok([n1, n2]) | _ => Error(impossibleError) } let twoNumberInputs = (inputs: array): result<(float, float), string> => { switch inputs { | [Number(n1), Number(n2)] => Ok(n1, n2) | _ => Error(impossibleError) } } let twoDistOrNumber = (values: array): result<(distOrNumber, distOrNumber), string> => { switch values { | [DistOrNumber(a1), DistOrNumber(a2)] => Ok(a1, a2) | _ => Error(impossibleError) } } let twoDistOrNumberFromRecord = (values: array) => values->recordWithTwoArgsToValues->E.R.bind(twoDistOrNumber) } module Process = { let twoDistsOrNumbersToDist = ( ~fn: ((float, float)) => result, ~values: (distOrNumber, distOrNumber), ) => { let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) let sampleSetToExpressionValue = ( b: Belt.Result.t, ) => switch b { | Ok(r) => Ok(ReducerInterface_ExpressionValue.EvDistribution(SampleSet(r))) | Error(d) => Error(DistributionTypes.Error.toString(d)) } let mapFnResult = r => switch r { | Ok(r) => Ok(GenericDist.sample(r)) | Error(r) => Error(Operation.Other(r)) } let singleVarSample = (a, fn) => { let sampleSetResult = toSampleSet(a) |> E.R2.bind(dist => SampleSetDist.samplesMap( ~fn=f => fn(f)->mapFnResult, dist, )->E.R2.errMap(r => DistributionTypes.SampleSetError(r)) ) sampleSetResult->sampleSetToExpressionValue } switch values { | (Number(a1), Number(a2)) => fn((a1, a2))->E.R2.fmap(Wrappers.evDistribution) | (Dist(a1), Number(a2)) => singleVarSample(a1, r => fn((r, a2))) | (Number(a1), Dist(a2)) => singleVarSample(a2, r => fn((a1, r))) | (Dist(a1), Dist(a2)) => { let altFn = (a, b) => fn((a, b))->mapFnResult let sampleSetResult = E.R.merge(toSampleSet(a1), toSampleSet(a2)) ->E.R2.errMap(DistributionTypes.Error.toString) ->E.R.bind(((t1, t2)) => { SampleSetDist.map2(~fn=altFn, ~t1, ~t2)->E.R2.errMap(Operation.Error.toString) }) ->E.R2.errMap(r => DistributionTypes.OtherError(r)) sampleSetResult->sampleSetToExpressionValue } } } let twoDistsOrNumbersToDistUsingSymbolicDist = ( ~fn: ((float, float)) => result, ~values, ) => { twoDistsOrNumbersToDist(~fn=r => r->fn->E.R2.fmap(Wrappers.symbolic), ~values) } } module TwoArgDist = { let process = (~fn, r) => r->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) let mkRegular = (name, fn) => { Function.makeDefinition(~name, ~inputs=[I_DistOrNumber, I_DistOrNumber], ~run=inputs => inputs->Prepare.twoDistOrNumber->process(~fn) ) } let mkDef90th = (name, fn) => { Function.makeDefinition( ~name, ~inputs=[I_Record([("p5", I_DistOrNumber), ("p95", I_DistOrNumber)])], ~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn), ) } let mkDefMeanStdev = (name, fn) => { Function.makeDefinition( ~name, ~inputs=[I_Record([("mean", I_DistOrNumber), ("stdev", I_DistOrNumber)])], ~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn), ) } }