Converted params to env, named several arguments

This commit is contained in:
Ozzie Gooen 2022-03-31 14:07:39 -04:00
parent 4702cf3e5e
commit 4b3f24b38d
5 changed files with 91 additions and 82 deletions

View File

@ -1,7 +1,7 @@
open Jest open Jest
open Expect open Expect
let params: GenericDist_GenericOperation.params = { let env: GenericDist_GenericOperation.env = {
sampleCount: 100, sampleCount: 100,
xyPointLength: 100, xyPointLength: 100,
} }
@ -14,8 +14,8 @@ let uniformDist: GenericDist_Types.genericDist = #Symbolic(#Uniform({low: 9.0, h
let {toFloat, toDist, toString, toError} = module(GenericDist_GenericOperation.Output) let {toFloat, toDist, toString, toError} = module(GenericDist_GenericOperation.Output)
let {run} = module(GenericDist_GenericOperation) let {run} = module(GenericDist_GenericOperation)
let {fmap} = module(GenericDist_GenericOperation.Output) let {fmap} = module(GenericDist_GenericOperation.Output)
let run = run(params) let run = run(~env)
let outputMap = fmap(params) let outputMap = fmap(~env)
let toExt: option<'a> => 'a = E.O.toExt( let toExt: option<'a> => 'a = E.O.toExt(
"Should be impossible to reach (This error is in test file)", "Should be impossible to reach (This error is in test file)",
) )
@ -29,7 +29,7 @@ describe("normalize", () => {
describe("mean", () => { describe("mean", () => {
test("for a normal distribution", () => { test("for a normal distribution", () => {
let result = GenericDist_GenericOperation.run(params, #fromDist(#toFloat(#Mean), normalDist)) let result = GenericDist_GenericOperation.run(~env, #fromDist(#toFloat(#Mean), normalDist))
expect(result)->toEqual(Float(5.0)) expect(result)->toEqual(Float(5.0))
}) })
}) })

View File

@ -29,14 +29,14 @@ let normalize = (t: t) =>
| #SampleSet(_) => t | #SampleSet(_) => t
} }
let operationToFloat = ( let toFloatOperation = (
t, t,
~toPointSetFn: toPointSetFn, ~toPointSetFn: toPointSetFn,
~operation: Operation.distToFloatOperation, ~distToFloatOperation: Operation.distToFloatOperation,
) => { ) => {
let symbolicSolution = switch t { let symbolicSolution = switch t {
| #Symbolic(r) => | #Symbolic(r) =>
switch SymbolicDist.T.operate(operation, r) { switch SymbolicDist.T.operate(distToFloatOperation, r) {
| Ok(f) => Some(f) | Ok(f) => Some(f)
| _ => None | _ => None
} }
@ -45,28 +45,26 @@ let operationToFloat = (
switch symbolicSolution { switch symbolicSolution {
| Some(r) => Ok(r) | Some(r) => Ok(r)
| None => toPointSetFn(t)->E.R2.fmap(PointSetDist.operate(operation)) | None => toPointSetFn(t)->E.R2.fmap(PointSetDist.operate(distToFloatOperation))
} }
} }
//TODO: Refactor this bit.
let defaultSamplingInputs: SamplingInputs.samplingInputs = {
sampleCount: 10000,
outputXYPoints: 10000,
pointSetDistLength: 1000,
kernelWidth: None,
}
//Todo: If it's a pointSet, but the xyPointLenght is different from what it has, it should change. //Todo: If it's a pointSet, but the xyPointLenght is different from what it has, it should change.
// This is tricky because the case of discrete distributions. // This is tricky because the case of discrete distributions.
let toPointSet = (t, xyPointLength): result<PointSetTypes.pointSetDist, error> => { // Also, change the outputXYPoints/pointSetDistLength details
let toPointSet = (~xyPointLength, ~sampleCount, t): result<PointSetTypes.pointSetDist, error> => {
switch t { switch t {
| #PointSet(pointSet) => Ok(pointSet) | #PointSet(pointSet) => Ok(pointSet)
| #Symbolic(r) => Ok(SymbolicDist.T.toPointSetDist(xyPointLength, r)) | #Symbolic(r) => Ok(SymbolicDist.T.toPointSetDist(xyPointLength, r))
| #SampleSet(r) => { | #SampleSet(r) => {
let response = SampleSet.toPointSetDist( let response = SampleSet.toPointSetDist(
~samples=r, ~samples=r,
~samplingInputs=defaultSamplingInputs, ~samplingInputs={
sampleCount: sampleCount,
outputXYPoints: xyPointLength,
pointSetDistLength: xyPointLength,
kernelWidth: None,
},
(), (),
).pointSetDist ).pointSetDist
switch response { switch response {
@ -119,13 +117,13 @@ let truncate = Truncate.run
*/ */
module AlgebraicCombination = { module AlgebraicCombination = {
let tryAnalyticalSimplification = ( let tryAnalyticalSimplification = (
operation: GenericDist_Types.Operation.arithmeticOperation, arithmeticOperation: GenericDist_Types.Operation.arithmeticOperation,
t1: t, t1: t,
t2: t, t2: t,
): option<result<SymbolicDistTypes.symbolicDist, string>> => ): option<result<SymbolicDistTypes.symbolicDist, string>> =>
switch (operation, t1, t2) { switch (arithmeticOperation, t1, t2) {
| (operation, #Symbolic(d1), #Symbolic(d2)) => | (arithmeticOperation, #Symbolic(d1), #Symbolic(d2)) =>
switch SymbolicDist.T.tryAnalyticalSimplification(d1, d2, operation) { switch SymbolicDist.T.tryAnalyticalSimplification(d1, d2, arithmeticOperation) {
| #AnalyticalSolution(symbolicDist) => Some(Ok(symbolicDist)) | #AnalyticalSolution(symbolicDist) => Some(Ok(symbolicDist))
| #Error(er) => Some(Error(er)) | #Error(er) => Some(Error(er))
| #NoSolution => None | #NoSolution => None
@ -135,23 +133,23 @@ module AlgebraicCombination = {
let runConvolution = ( let runConvolution = (
toPointSet: toPointSetFn, toPointSet: toPointSetFn,
operation: GenericDist_Types.Operation.arithmeticOperation, arithmeticOperation: GenericDist_Types.Operation.arithmeticOperation,
t1: t, t1: t,
t2: t, t2: t,
) => ) =>
E.R.merge(toPointSet(t1), toPointSet(t2))->E.R2.fmap(((a, b)) => E.R.merge(toPointSet(t1), toPointSet(t2))->E.R2.fmap(((a, b)) =>
PointSetDist.combineAlgebraically(operation, a, b) PointSetDist.combineAlgebraically(arithmeticOperation, a, b)
) )
let runMonteCarlo = ( let runMonteCarlo = (
toSampleSet: toSampleSetFn, toSampleSet: toSampleSetFn,
operation: GenericDist_Types.Operation.arithmeticOperation, arithmeticOperation: GenericDist_Types.Operation.arithmeticOperation,
t1: t, t1: t,
t2: t, t2: t,
) => { ) => {
let operation = Operation.Algebraic.toFn(operation) let arithmeticOperation = Operation.Algebraic.toFn(arithmeticOperation)
E.R.merge(toSampleSet(t1), toSampleSet(t2))->E.R2.fmap(((a, b)) => { E.R.merge(toSampleSet(t1), toSampleSet(t2))->E.R2.fmap(((a, b)) => {
Belt.Array.zip(a, b)->E.A2.fmap(((a, b)) => operation(a, b)) Belt.Array.zip(a, b)->E.A2.fmap(((a, b)) => arithmeticOperation(a, b))
}) })
} }
@ -175,18 +173,18 @@ module AlgebraicCombination = {
t1: t, t1: t,
~toPointSetFn: toPointSetFn, ~toPointSetFn: toPointSetFn,
~toSampleSetFn: toSampleSetFn, ~toSampleSetFn: toSampleSetFn,
~operation, ~arithmeticOperation,
~t2: t, ~t2: t,
): result<t, error> => { ): result<t, error> => {
switch tryAnalyticalSimplification(operation, t1, t2) { switch tryAnalyticalSimplification(arithmeticOperation, t1, t2) {
| Some(Ok(symbolicDist)) => Ok(#Symbolic(symbolicDist)) | Some(Ok(symbolicDist)) => Ok(#Symbolic(symbolicDist))
| Some(Error(e)) => Error(Other(e)) | Some(Error(e)) => Error(Other(e))
| None => | None =>
switch chooseConvolutionOrMonteCarlo(t1, t2) { switch chooseConvolutionOrMonteCarlo(t1, t2) {
| #CalculateWithMonteCarlo => | #CalculateWithMonteCarlo =>
runMonteCarlo(toSampleSetFn, operation, t1, t2)->E.R2.fmap(r => #SampleSet(r)) runMonteCarlo(toSampleSetFn, arithmeticOperation, t1, t2)->E.R2.fmap(r => #SampleSet(r))
| #CalculateWithConvolution => | #CalculateWithConvolution =>
runConvolution(toPointSetFn, operation, t1, t2)->E.R2.fmap(r => #PointSet(r)) runConvolution(toPointSetFn, arithmeticOperation, t1, t2)->E.R2.fmap(r => #PointSet(r))
} }
} }
} }
@ -195,13 +193,19 @@ module AlgebraicCombination = {
let algebraicCombination = AlgebraicCombination.run let algebraicCombination = AlgebraicCombination.run
//TODO: Add faster pointwiseCombine fn //TODO: Add faster pointwiseCombine fn
let pointwiseCombination = (t1: t, ~toPointSetFn: toPointSetFn, ~operation, ~t2: t): result< let pointwiseCombination = (
t, t1: t,
error, ~toPointSetFn: toPointSetFn,
> => { ~arithmeticOperation,
~t2: t,
): result<t, error> => {
E.R.merge(toPointSetFn(t1), toPointSetFn(t2)) E.R.merge(toPointSetFn(t1), toPointSetFn(t2))
->E.R2.fmap(((t1, t2)) => ->E.R2.fmap(((t1, t2)) =>
PointSetDist.combinePointwise(GenericDist_Types.Operation.arithmeticToFn(operation), t1, t2) PointSetDist.combinePointwise(
GenericDist_Types.Operation.arithmeticToFn(arithmeticOperation),
t1,
t2,
)
) )
->E.R2.fmap(r => #PointSet(r)) ->E.R2.fmap(r => #PointSet(r))
} }
@ -209,17 +213,17 @@ let pointwiseCombination = (t1: t, ~toPointSetFn: toPointSetFn, ~operation, ~t2:
let pointwiseCombinationFloat = ( let pointwiseCombinationFloat = (
t: t, t: t,
~toPointSetFn: toPointSetFn, ~toPointSetFn: toPointSetFn,
~operation: GenericDist_Types.Operation.arithmeticOperation, ~arithmeticOperation: GenericDist_Types.Operation.arithmeticOperation,
~float: float, ~float: float,
): result<t, error> => { ): result<t, error> => {
let m = switch operation { let m = switch arithmeticOperation {
| #Add | #Subtract => Error(GenericDist_Types.DistributionVerticalShiftIsInvalid) | #Add | #Subtract => Error(GenericDist_Types.DistributionVerticalShiftIsInvalid)
| (#Multiply | #Divide | #Exponentiate | #Log) as operation => | (#Multiply | #Divide | #Exponentiate | #Log) as arithmeticOperation =>
toPointSetFn(t)->E.R2.fmap(t => { toPointSetFn(t)->E.R2.fmap(t => {
//TODO: Move to PointSet codebase //TODO: Move to PointSet codebase
let fn = (secondary, main) => Operation.Scale.toFn(operation, main, secondary) let fn = (secondary, main) => Operation.Scale.toFn(arithmeticOperation, main, secondary)
let integralSumCacheFn = Operation.Scale.toIntegralSumCacheFn(operation) let integralSumCacheFn = Operation.Scale.toIntegralSumCacheFn(arithmeticOperation)
let integralCacheFn = Operation.Scale.toIntegralCacheFn(operation) let integralCacheFn = Operation.Scale.toIntegralCacheFn(arithmeticOperation)
PointSetDist.T.mapY( PointSetDist.T.mapY(
~integralSumCacheFn=integralSumCacheFn(float), ~integralSumCacheFn=integralSumCacheFn(float),
~integralCacheFn=integralCacheFn(float), ~integralCacheFn=integralCacheFn(float),

View File

@ -13,13 +13,17 @@ let toString: t => string
let normalize: t => t let normalize: t => t
let operationToFloat: ( let toFloatOperation: (
t, t,
~toPointSetFn: toPointSetFn, ~toPointSetFn: toPointSetFn,
~operation: Operation.distToFloatOperation, ~distToFloatOperation: Operation.distToFloatOperation,
) => result<float, error> ) => result<float, error>
let toPointSet: (t, int) => result<PointSetTypes.pointSetDist, error> let toPointSet: (
~xyPointLength: int,
~sampleCount: int,
t,
) => result<PointSetTypes.pointSetDist, error>
let truncate: ( let truncate: (
t, t,
@ -33,21 +37,21 @@ let algebraicCombination: (
t, t,
~toPointSetFn: toPointSetFn, ~toPointSetFn: toPointSetFn,
~toSampleSetFn: toSampleSetFn, ~toSampleSetFn: toSampleSetFn,
~operation: GenericDist_Types.Operation.arithmeticOperation, ~arithmeticOperation: GenericDist_Types.Operation.arithmeticOperation,
~t2: t, ~t2: t,
) => result<t, error> ) => result<t, error>
let pointwiseCombination: ( let pointwiseCombination: (
t, t,
~toPointSetFn: toPointSetFn, ~toPointSetFn: toPointSetFn,
~operation: GenericDist_Types.Operation.arithmeticOperation, ~arithmeticOperation: GenericDist_Types.Operation.arithmeticOperation,
~t2: t, ~t2: t,
) => result<t, error> ) => result<t, error>
let pointwiseCombinationFloat: ( let pointwiseCombinationFloat: (
t, t,
~toPointSetFn: toPointSetFn, ~toPointSetFn: toPointSetFn,
~operation: GenericDist_Types.Operation.arithmeticOperation, ~arithmeticOperation: GenericDist_Types.Operation.arithmeticOperation,
~float: float, ~float: float,
) => result<t, error> ) => result<t, error>

View File

@ -1,10 +1,10 @@
type operation = GenericDist_Types.Operation.genericFunctionCallInfo type functionCallInfo = GenericDist_Types.Operation.genericFunctionCallInfo
type genericDist = GenericDist_Types.genericDist type genericDist = GenericDist_Types.genericDist
type error = GenericDist_Types.error type error = GenericDist_Types.error
// TODO: It could be great to use a cache for some calculations (basically, do memoization). Also, better analytics/tracking could go a long way. // TODO: It could be great to use a cache for some calculations (basically, do memoization). Also, better analytics/tracking could go a long way.
type params = { type env = {
sampleCount: int, sampleCount: int,
xyPointLength: int, xyPointLength: int,
} }
@ -62,22 +62,22 @@ module OutputLocal = {
} }
} }
let rec run = (extra, fnName: operation): outputType => { let rec run = (~env, functionCallInfo: functionCallInfo): outputType => {
let {sampleCount, xyPointLength} = extra let {sampleCount, xyPointLength} = env
let reCall = (~extra=extra, ~fnName=fnName, ()) => { let reCall = (~env=env, ~functionCallInfo=functionCallInfo, ()) => {
run(extra, fnName) run(~env, functionCallInfo)
} }
let toPointSetFn = r => { let toPointSetFn = r => {
switch reCall(~fnName=#fromDist(#toDist(#toPointSet), r), ()) { switch reCall(~functionCallInfo=#fromDist(#toDist(#toPointSet), r), ()) {
| Dist(#PointSet(p)) => Ok(p) | Dist(#PointSet(p)) => Ok(p)
| e => Error(OutputLocal.toErrorOrUnreachable(e)) | e => Error(OutputLocal.toErrorOrUnreachable(e))
} }
} }
let toSampleSetFn = r => { let toSampleSetFn = r => {
switch reCall(~fnName=#fromDist(#toDist(#toSampleSet(sampleCount)), r), ()) { switch reCall(~functionCallInfo=#fromDist(#toDist(#toSampleSet(sampleCount)), r), ()) {
| Dist(#SampleSet(p)) => Ok(p) | Dist(#SampleSet(p)) => Ok(p)
| e => Error(OutputLocal.toErrorOrUnreachable(e)) | e => Error(OutputLocal.toErrorOrUnreachable(e))
} }
@ -85,20 +85,20 @@ let rec run = (extra, fnName: operation): outputType => {
let scaleMultiply = (r, weight) => let scaleMultiply = (r, weight) =>
reCall( reCall(
~fnName=#fromDist(#toDistCombination(#Pointwise, #Multiply, #Float(weight)), r), ~functionCallInfo=#fromDist(#toDistCombination(#Pointwise, #Multiply, #Float(weight)), r),
(), (),
)->OutputLocal.toDistR )->OutputLocal.toDistR
let pointwiseAdd = (r1, r2) => let pointwiseAdd = (r1, r2) =>
reCall( reCall(
~fnName=#fromDist(#toDistCombination(#Pointwise, #Add, #Dist(r2)), r1), ~functionCallInfo=#fromDist(#toDistCombination(#Pointwise, #Add, #Dist(r2)), r1),
(), (),
)->OutputLocal.toDistR )->OutputLocal.toDistR
let fromDistFn = (subFnName: GenericDist_Types.Operation.fromDist, dist: genericDist) => let fromDistFn = (subFnName: GenericDist_Types.Operation.fromDist, dist: genericDist) =>
switch subFnName { switch subFnName {
| #toFloat(fnName) => | #toFloat(distToFloatOperation) =>
GenericDist.operationToFloat(dist, ~toPointSetFn, ~operation=fnName) GenericDist.toFloatOperation(dist, ~toPointSetFn, ~distToFloatOperation)
->E.R2.fmap(r => Float(r)) ->E.R2.fmap(r => Float(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| #toString => dist->GenericDist.toString->String | #toString => dist->GenericDist.toString->String
@ -113,33 +113,33 @@ let rec run = (extra, fnName: operation): outputType => {
->OutputLocal.fromResult ->OutputLocal.fromResult
| #toDist(#toPointSet) => | #toDist(#toPointSet) =>
dist dist
->GenericDist.toPointSet(xyPointLength) ->GenericDist.toPointSet(~xyPointLength, ~sampleCount)
->E.R2.fmap(r => Dist(#PointSet(r))) ->E.R2.fmap(r => Dist(#PointSet(r)))
->OutputLocal.fromResult ->OutputLocal.fromResult
| #toDist(#toSampleSet(n)) => | #toDist(#toSampleSet(n)) =>
dist->GenericDist.sampleN(n)->E.R2.fmap(r => Dist(#SampleSet(r)))->OutputLocal.fromResult dist->GenericDist.sampleN(n)->E.R2.fmap(r => Dist(#SampleSet(r)))->OutputLocal.fromResult
| #toDistCombination(#Algebraic, _, #Float(_)) => GenDistError(NotYetImplemented) | #toDistCombination(#Algebraic, _, #Float(_)) => GenDistError(NotYetImplemented)
| #toDistCombination(#Algebraic, operation, #Dist(t2)) => | #toDistCombination(#Algebraic, arithmeticOperation, #Dist(t2)) =>
dist dist
->GenericDist.algebraicCombination(~toPointSetFn, ~toSampleSetFn, ~operation, ~t2) ->GenericDist.algebraicCombination(~toPointSetFn, ~toSampleSetFn, ~arithmeticOperation, ~t2)
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| #toDistCombination(#Pointwise, operation, #Dist(t2)) => | #toDistCombination(#Pointwise, arithmeticOperation, #Dist(t2)) =>
dist dist
->GenericDist.pointwiseCombination(~toPointSetFn, ~operation, ~t2) ->GenericDist.pointwiseCombination(~toPointSetFn, ~arithmeticOperation, ~t2)
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
| #toDistCombination(#Pointwise, operation, #Float(float)) => | #toDistCombination(#Pointwise, arithmeticOperation, #Float(float)) =>
dist dist
->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~operation, ~float) ->GenericDist.pointwiseCombinationFloat(~toPointSetFn, ~arithmeticOperation, ~float)
->E.R2.fmap(r => Dist(r)) ->E.R2.fmap(r => Dist(r))
->OutputLocal.fromResult ->OutputLocal.fromResult
} }
switch fnName { switch functionCallInfo {
| #fromDist(subFnName, dist) => fromDistFn(subFnName, dist) | #fromDist(subFnName, dist) => fromDistFn(subFnName, dist)
| #fromFloat(subFnName, float) => | #fromFloat(subFnName, float) =>
reCall(~fnName=#fromDist(subFnName, GenericDist.fromFloat(float)), ()) reCall(~functionCallInfo=#fromDist(subFnName, GenericDist.fromFloat(float)), ())
| #mixture(dists) => | #mixture(dists) =>
dists dists
->GenericDist.mixture(~scaleMultiplyFn=scaleMultiply, ~pointwiseAddFn=pointwiseAdd) ->GenericDist.mixture(~scaleMultiplyFn=scaleMultiply, ~pointwiseAddFn=pointwiseAdd)
@ -148,24 +148,25 @@ let rec run = (extra, fnName: operation): outputType => {
} }
} }
let runFromDist = (extra, fnName, dist) => run(extra, #fromDist(fnName, dist)) let runFromDist = (~env, ~functionCallInfo, dist) => run(~env, #fromDist(functionCallInfo, dist))
let runFromFloat = (extra, fnName, float) => run(extra, #fromFloat(fnName, float)) let runFromFloat = (~env, ~functionCallInfo, float) =>
run(~env, #fromFloat(functionCallInfo, float))
module Output = { module Output = {
include OutputLocal include OutputLocal
let fmap = ( let fmap = (
extra, ~env,
input: outputType, input: outputType,
fn: GenericDist_Types.Operation.singleParamaterFunction, functionCallInfo: GenericDist_Types.Operation.singleParamaterFunction,
): outputType => { ): outputType => {
let newFnCall: result<operation, error> = switch (fn, input) { let newFnCall: result<functionCallInfo, error> = switch (functionCallInfo, input) {
| (#fromDist(fromDist), Dist(o)) => Ok(#fromDist(fromDist, o)) | (#fromDist(fromDist), Dist(o)) => Ok(#fromDist(fromDist, o))
| (#fromFloat(fromDist), Float(o)) => Ok(#fromFloat(fromDist, o)) | (#fromFloat(fromDist), Float(o)) => Ok(#fromFloat(fromDist, o))
| (_, GenDistError(r)) => Error(r) | (_, GenDistError(r)) => Error(r)
| (#fromDist(_), _) => Error(Other("Expected dist, got something else")) | (#fromDist(_), _) => Error(Other("Expected dist, got something else"))
| (#fromFloat(_), _) => Error(Other("Expected float, got something else")) | (#fromFloat(_), _) => Error(Other("Expected float, got something else"))
} }
newFnCall->E.R2.fmap(r => run(extra, r))->OutputLocal.fromResult newFnCall->E.R2.fmap(run(~env))->OutputLocal.fromResult
} }
} }

View File

@ -1,4 +1,4 @@
type params = { type env = {
sampleCount: int, sampleCount: int,
xyPointLength: int, xyPointLength: int,
} }
@ -9,13 +9,13 @@ type outputType =
| String(string) | String(string)
| GenDistError(GenericDist_Types.error) | GenDistError(GenericDist_Types.error)
let run: (params, GenericDist_Types.Operation.genericFunctionCallInfo) => outputType let run: (~env: env, GenericDist_Types.Operation.genericFunctionCallInfo) => outputType
let runFromDist: ( let runFromDist: (
params, ~env: env,
GenericDist_Types.Operation.fromDist, ~functionCallInfo: GenericDist_Types.Operation.fromDist,
GenericDist_Types.genericDist, GenericDist_Types.genericDist,
) => outputType ) => outputType
let runFromFloat: (params, GenericDist_Types.Operation.fromDist, float) => outputType let runFromFloat: (~env: env, ~functionCallInfo: GenericDist_Types.Operation.fromDist, float) => outputType
module Output: { module Output: {
type t = outputType type t = outputType
@ -24,5 +24,5 @@ module Output: {
let toFloat: t => option<float> let toFloat: t => option<float>
let toString: t => option<string> let toString: t => option<string>
let toError: t => option<GenericDist_Types.error> let toError: t => option<GenericDist_Types.error>
let fmap: (params, t, GenericDist_Types.Operation.singleParamaterFunction) => t let fmap: (~env: env, t, GenericDist_Types.Operation.singleParamaterFunction) => t
} }