Converting final files to rescript
This commit is contained in:
parent
3019a58962
commit
9463914204
|
@ -1,5 +1,5 @@
|
||||||
open Jest;
|
open Jest
|
||||||
open Expect;
|
open Expect
|
||||||
/*
|
/*
|
||||||
let makeTest = (~only=false, str, item1, item2) =>
|
let makeTest = (~only=false, str, item1, item2) =>
|
||||||
only
|
only
|
|
@ -1,25 +0,0 @@
|
||||||
open Jest;
|
|
||||||
open Expect;
|
|
||||||
|
|
||||||
let makeTest = (~only=false, str, item1, item2) =>
|
|
||||||
only
|
|
||||||
? Only.test(str, () =>
|
|
||||||
expect(item1) |> toEqual(item2)
|
|
||||||
)
|
|
||||||
: test(str, () =>
|
|
||||||
expect(item1) |> toEqual(item2)
|
|
||||||
);
|
|
||||||
|
|
||||||
describe("Lodash", () => {
|
|
||||||
describe("Lodash", () => {
|
|
||||||
makeTest(~only=true, "Foo", Jstat.Normal.mean(5.0,2.0), 5.0);
|
|
||||||
makeTest("min", Lodash.min([|1, 3, 4|]), 1);
|
|
||||||
makeTest("max", Lodash.max([|1, 3, 4|]), 4);
|
|
||||||
makeTest("uniq", Lodash.uniq([|1, 3, 4, 4|]), [|1, 3, 4|]);
|
|
||||||
makeTest(
|
|
||||||
"countBy",
|
|
||||||
Lodash.countBy([|1, 3, 4, 4|], r => r),
|
|
||||||
Js.Dict.fromArray([|("1", 1), ("3", 1), ("4", 2)|]),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
});
|
|
20
packages/squiggle-lang/__tests__/Lodash__test.res
Normal file
20
packages/squiggle-lang/__tests__/Lodash__test.res
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
|
||||||
|
let makeTest = (~only=false, str, item1, item2) =>
|
||||||
|
only
|
||||||
|
? Only.test(str, () => expect(item1) |> toEqual(item2))
|
||||||
|
: test(str, () => expect(item1) |> toEqual(item2))
|
||||||
|
|
||||||
|
describe("Lodash", () =>
|
||||||
|
describe("Lodash", () => {
|
||||||
|
makeTest("min", Lodash.min([1, 3, 4]), 1)
|
||||||
|
makeTest("max", Lodash.max([1, 3, 4]), 4)
|
||||||
|
makeTest("uniq", Lodash.uniq([1, 3, 4, 4]), [1, 3, 4])
|
||||||
|
makeTest(
|
||||||
|
"countBy",
|
||||||
|
Lodash.countBy([1, 3, 4, 4], r => r),
|
||||||
|
Js.Dict.fromArray([("1", 1), ("3", 1), ("4", 2)]),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
|
@ -1,258 +0,0 @@
|
||||||
open TypeSystem;
|
|
||||||
|
|
||||||
let wrongInputsError = (r: array(typedValue)) => {
|
|
||||||
let inputs = r |> E.A.fmap(TypedValue.toString) |>Js.String.concatMany(_, ",");
|
|
||||||
Js.log3("Inputs were", inputs, r);
|
|
||||||
Error("Wrong inputs. The inputs were:" ++ inputs);
|
|
||||||
};
|
|
||||||
|
|
||||||
let to_: (float, float) => result(node, string) =
|
|
||||||
(low, high) =>
|
|
||||||
switch (low, high) {
|
|
||||||
| (low, high) when low <= 0.0 && low < high =>
|
|
||||||
Ok(`SymbolicDist(SymbolicDist.Normal.from90PercentCI(low, high)))
|
|
||||||
| (low, high) when low < high =>
|
|
||||||
Ok(`SymbolicDist(SymbolicDist.Lognormal.from90PercentCI(low, high)))
|
|
||||||
| (_, _) => Error("Low value must be less than high value.")
|
|
||||||
};
|
|
||||||
|
|
||||||
let makeSymbolicFromTwoFloats = (name, fn) =>
|
|
||||||
Function.T.make(
|
|
||||||
~name,
|
|
||||||
~outputType=`SamplingDistribution,
|
|
||||||
~inputTypes=[|`Float, `Float|],
|
|
||||||
~run=
|
|
||||||
fun
|
|
||||||
| [|`Float(a), `Float(b)|] => Ok(`SymbolicDist(fn(a, b)))
|
|
||||||
| e => wrongInputsError(e),
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let makeSymbolicFromOneFloat = (name, fn) =>
|
|
||||||
Function.T.make(
|
|
||||||
~name,
|
|
||||||
~outputType=`SamplingDistribution,
|
|
||||||
~inputTypes=[|`Float|],
|
|
||||||
~run=
|
|
||||||
fun
|
|
||||||
| [|`Float(a)|] => Ok(`SymbolicDist(fn(a)))
|
|
||||||
| e => wrongInputsError(e),
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let makeDistFloat = (name, fn) =>
|
|
||||||
Function.T.make(
|
|
||||||
~name,
|
|
||||||
~outputType=`SamplingDistribution,
|
|
||||||
~inputTypes=[|`SamplingDistribution, `Float|],
|
|
||||||
~run=
|
|
||||||
fun
|
|
||||||
| [|`SamplingDist(a), `Float(b)|] => fn(a, b)
|
|
||||||
| [|`RenderedDist(a), `Float(b)|] => fn(`RenderedDist(a), b)
|
|
||||||
| e => wrongInputsError(e),
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let makeRenderedDistFloat = (name, fn) =>
|
|
||||||
Function.T.make(
|
|
||||||
~name,
|
|
||||||
~outputType=`RenderedDistribution,
|
|
||||||
~inputTypes=[|`RenderedDistribution, `Float|],
|
|
||||||
~shouldCoerceTypes=true,
|
|
||||||
~run=
|
|
||||||
fun
|
|
||||||
| [|`RenderedDist(a), `Float(b)|] => fn(a, b)
|
|
||||||
| e => wrongInputsError(e),
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let makeDist = (name, fn) =>
|
|
||||||
Function.T.make(
|
|
||||||
~name,
|
|
||||||
~outputType=`SamplingDistribution,
|
|
||||||
~inputTypes=[|`SamplingDistribution|],
|
|
||||||
~run=
|
|
||||||
fun
|
|
||||||
| [|`SamplingDist(a)|] => fn(a)
|
|
||||||
| [|`RenderedDist(a)|] => fn(`RenderedDist(a))
|
|
||||||
| e => wrongInputsError(e),
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let floatFromDist =
|
|
||||||
(
|
|
||||||
distToFloatOp: ExpressionTypes.distToFloatOperation,
|
|
||||||
t: TypeSystem.samplingDist,
|
|
||||||
)
|
|
||||||
: result(node, string) => {
|
|
||||||
switch (t) {
|
|
||||||
| `SymbolicDist(s) =>
|
|
||||||
SymbolicDist.T.operate(distToFloatOp, s)
|
|
||||||
|> E.R.bind(_, v => Ok(`SymbolicDist(`Float(v))))
|
|
||||||
| `RenderedDist(rs) =>
|
|
||||||
Shape.operate(distToFloatOp, rs) |> (v => Ok(`SymbolicDist(`Float(v))))
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let verticalScaling = (scaleOp, rs, scaleBy) => {
|
|
||||||
// scaleBy has to be a single float, otherwise we'll return an error.
|
|
||||||
let fn = (secondary, main) =>
|
|
||||||
Operation.Scale.toFn(scaleOp, main, secondary);
|
|
||||||
let integralSumCacheFn = Operation.Scale.toIntegralSumCacheFn(scaleOp);
|
|
||||||
let integralCacheFn = Operation.Scale.toIntegralCacheFn(scaleOp);
|
|
||||||
Ok(
|
|
||||||
`RenderedDist(
|
|
||||||
Shape.T.mapY(
|
|
||||||
~integralSumCacheFn=integralSumCacheFn(scaleBy),
|
|
||||||
~integralCacheFn=integralCacheFn(scaleBy),
|
|
||||||
~fn=fn(scaleBy),
|
|
||||||
rs,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
module Multimodal = {
|
|
||||||
let getByNameResult = ExpressionTypes.ExpressionTree.Hash.getByNameResult;
|
|
||||||
|
|
||||||
let _paramsToDistsAndWeights = (r: array(typedValue)) =>
|
|
||||||
switch (r) {
|
|
||||||
| [|`Hash(r)|] =>
|
|
||||||
let dists =
|
|
||||||
getByNameResult(r, "dists")
|
|
||||||
->E.R.bind(TypeSystem.TypedValue.toArray)
|
|
||||||
->E.R.bind(r =>
|
|
||||||
r
|
|
||||||
|> E.A.fmap(TypeSystem.TypedValue.toDist)
|
|
||||||
|> E.A.R.firstErrorOrOpen
|
|
||||||
);
|
|
||||||
let weights =
|
|
||||||
getByNameResult(r, "weights")
|
|
||||||
->E.R.bind(TypeSystem.TypedValue.toArray)
|
|
||||||
->E.R.bind(r =>
|
|
||||||
r
|
|
||||||
|> E.A.fmap(TypeSystem.TypedValue.toFloat)
|
|
||||||
|> E.A.R.firstErrorOrOpen
|
|
||||||
);
|
|
||||||
|
|
||||||
E.R.merge(dists, weights)
|
|
||||||
|> E.R.fmap(((a, b)) =>
|
|
||||||
E.A.zipMaxLength(a, b)
|
|
||||||
|> E.A.fmap(((a, b)) =>
|
|
||||||
(a |> E.O.toExn(""), b |> E.O.default(1.0))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
| _ => Error("Needs items")
|
|
||||||
};
|
|
||||||
let _runner: array(typedValue) => result(node, string) =
|
|
||||||
r => {
|
|
||||||
let paramsToDistsAndWeights =
|
|
||||||
_paramsToDistsAndWeights(r)
|
|
||||||
|> E.R.fmap(
|
|
||||||
E.A.fmap(((dist, weight)) =>
|
|
||||||
`FunctionCall((
|
|
||||||
"scaleMultiply",
|
|
||||||
[|dist, `SymbolicDist(`Float(weight))|],
|
|
||||||
))
|
|
||||||
),
|
|
||||||
);
|
|
||||||
let pointwiseSum: result(node, string) =
|
|
||||||
paramsToDistsAndWeights->E.R.bind(
|
|
||||||
E.R.errorIfCondition(E.A.isEmpty, "Needs one input"),
|
|
||||||
)
|
|
||||||
|> E.R.fmap(r =>
|
|
||||||
r
|
|
||||||
|> Js.Array.sliceFrom(1)
|
|
||||||
|> E.A.fold_left(
|
|
||||||
(acc, x) => {`PointwiseCombination((`Add, acc, x))},
|
|
||||||
E.A.unsafe_get(r, 0),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
pointwiseSum;
|
|
||||||
};
|
|
||||||
|
|
||||||
let _function =
|
|
||||||
Function.T.make(
|
|
||||||
~name="multimodal",
|
|
||||||
~outputType=`SamplingDistribution,
|
|
||||||
~inputTypes=[|
|
|
||||||
`Hash([|
|
|
||||||
("dists", `Array(`SamplingDistribution)),
|
|
||||||
("weights", `Array(`Float)),
|
|
||||||
|]),
|
|
||||||
|],
|
|
||||||
~run=_runner,
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let all = [|
|
|
||||||
makeSymbolicFromTwoFloats("normal", SymbolicDist.Normal.make),
|
|
||||||
makeSymbolicFromTwoFloats("uniform", SymbolicDist.Uniform.make),
|
|
||||||
makeSymbolicFromTwoFloats("beta", SymbolicDist.Beta.make),
|
|
||||||
makeSymbolicFromTwoFloats("lognormal", SymbolicDist.Lognormal.make),
|
|
||||||
makeSymbolicFromTwoFloats(
|
|
||||||
"lognormalFromMeanAndStdDev",
|
|
||||||
SymbolicDist.Lognormal.fromMeanAndStdev,
|
|
||||||
),
|
|
||||||
makeSymbolicFromOneFloat("exponential", SymbolicDist.Exponential.make),
|
|
||||||
Function.T.make(
|
|
||||||
~name="to",
|
|
||||||
~outputType=`SamplingDistribution,
|
|
||||||
~inputTypes=[|`Float, `Float|],
|
|
||||||
~run=
|
|
||||||
fun
|
|
||||||
| [|`Float(a), `Float(b)|] => to_(a, b)
|
|
||||||
| e => wrongInputsError(e),
|
|
||||||
(),
|
|
||||||
),
|
|
||||||
Function.T.make(
|
|
||||||
~name="triangular",
|
|
||||||
~outputType=`SamplingDistribution,
|
|
||||||
~inputTypes=[|`Float, `Float, `Float|],
|
|
||||||
~run=
|
|
||||||
fun
|
|
||||||
| [|`Float(a), `Float(b), `Float(c)|] =>
|
|
||||||
SymbolicDist.Triangular.make(a, b, c)
|
|
||||||
|> E.R.fmap(r => `SymbolicDist(r))
|
|
||||||
| e => wrongInputsError(e),
|
|
||||||
(),
|
|
||||||
),
|
|
||||||
makeDistFloat("pdf", (dist, float) => floatFromDist(`Pdf(float), dist)),
|
|
||||||
makeDistFloat("inv", (dist, float) => floatFromDist(`Inv(float), dist)),
|
|
||||||
makeDistFloat("cdf", (dist, float) => floatFromDist(`Cdf(float), dist)),
|
|
||||||
makeDist("mean", dist => floatFromDist(`Mean, dist)),
|
|
||||||
makeDist("sample", dist => floatFromDist(`Sample, dist)),
|
|
||||||
Function.T.make(
|
|
||||||
~name="render",
|
|
||||||
~outputType=`RenderedDistribution,
|
|
||||||
~inputTypes=[|`RenderedDistribution|],
|
|
||||||
~run=
|
|
||||||
fun
|
|
||||||
| [|`RenderedDist(c)|] => Ok(`RenderedDist(c))
|
|
||||||
| e => wrongInputsError(e),
|
|
||||||
(),
|
|
||||||
),
|
|
||||||
Function.T.make(
|
|
||||||
~name="normalize",
|
|
||||||
~outputType=`SamplingDistribution,
|
|
||||||
~inputTypes=[|`SamplingDistribution|],
|
|
||||||
~run=
|
|
||||||
fun
|
|
||||||
| [|`SamplingDist(`SymbolicDist(c))|] => Ok(`SymbolicDist(c))
|
|
||||||
| [|`SamplingDist(`RenderedDist(c))|] =>
|
|
||||||
Ok(`RenderedDist(Shape.T.normalize(c)))
|
|
||||||
| e => wrongInputsError(e),
|
|
||||||
(),
|
|
||||||
),
|
|
||||||
makeRenderedDistFloat("scaleExp", (dist, float) =>
|
|
||||||
verticalScaling(`Exponentiate, dist, float)
|
|
||||||
),
|
|
||||||
makeRenderedDistFloat("scaleMultiply", (dist, float) =>
|
|
||||||
verticalScaling(`Multiply, dist, float)
|
|
||||||
),
|
|
||||||
makeRenderedDistFloat("scaleLog", (dist, float) =>
|
|
||||||
verticalScaling(`Log, dist, float)
|
|
||||||
),
|
|
||||||
Multimodal._function
|
|
||||||
|];
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
open TypeSystem
|
||||||
|
|
||||||
|
let wrongInputsError = (r: array<typedValue>) => {
|
||||||
|
let inputs = r |> E.A.fmap(TypedValue.toString) |> Js.String.concatMany(_, ",")
|
||||||
|
Js.log3("Inputs were", inputs, r)
|
||||||
|
Error("Wrong inputs. The inputs were:" ++ inputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
let to_: (float, float) => result<node, string> = (low, high) =>
|
||||||
|
switch (low, high) {
|
||||||
|
| (low, high) if low <= 0.0 && low < high =>
|
||||||
|
Ok(#SymbolicDist(SymbolicDist.Normal.from90PercentCI(low, high)))
|
||||||
|
| (low, high) if low < high =>
|
||||||
|
Ok(#SymbolicDist(SymbolicDist.Lognormal.from90PercentCI(low, high)))
|
||||||
|
| (_, _) => Error("Low value must be less than high value.")
|
||||||
|
}
|
||||||
|
|
||||||
|
let makeSymbolicFromTwoFloats = (name, fn) =>
|
||||||
|
Function.T.make(
|
||||||
|
~name,
|
||||||
|
~outputType=#SamplingDistribution,
|
||||||
|
~inputTypes=[#Float, #Float],
|
||||||
|
~run=x =>
|
||||||
|
switch x {
|
||||||
|
| [#Float(a), #Float(b)] => Ok(#SymbolicDist(fn(a, b)))
|
||||||
|
| e => wrongInputsError(e)
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
|
||||||
|
let makeSymbolicFromOneFloat = (name, fn) =>
|
||||||
|
Function.T.make(
|
||||||
|
~name,
|
||||||
|
~outputType=#SamplingDistribution,
|
||||||
|
~inputTypes=[#Float],
|
||||||
|
~run=x =>
|
||||||
|
switch x {
|
||||||
|
| [#Float(a)] => Ok(#SymbolicDist(fn(a)))
|
||||||
|
| e => wrongInputsError(e)
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
|
||||||
|
let makeDistFloat = (name, fn) =>
|
||||||
|
Function.T.make(
|
||||||
|
~name,
|
||||||
|
~outputType=#SamplingDistribution,
|
||||||
|
~inputTypes=[#SamplingDistribution, #Float],
|
||||||
|
~run=x =>
|
||||||
|
switch x {
|
||||||
|
| [#SamplingDist(a), #Float(b)] => fn(a, b)
|
||||||
|
| [#RenderedDist(a), #Float(b)] => fn(#RenderedDist(a), b)
|
||||||
|
| e => wrongInputsError(e)
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
|
||||||
|
let makeRenderedDistFloat = (name, fn) =>
|
||||||
|
Function.T.make(
|
||||||
|
~name,
|
||||||
|
~outputType=#RenderedDistribution,
|
||||||
|
~inputTypes=[#RenderedDistribution, #Float],
|
||||||
|
~shouldCoerceTypes=true,
|
||||||
|
~run=x =>
|
||||||
|
switch x {
|
||||||
|
| [#RenderedDist(a), #Float(b)] => fn(a, b)
|
||||||
|
| e => wrongInputsError(e)
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
|
||||||
|
let makeDist = (name, fn) =>
|
||||||
|
Function.T.make(
|
||||||
|
~name,
|
||||||
|
~outputType=#SamplingDistribution,
|
||||||
|
~inputTypes=[#SamplingDistribution],
|
||||||
|
~run=x =>
|
||||||
|
switch x {
|
||||||
|
| [#SamplingDist(a)] => fn(a)
|
||||||
|
| [#RenderedDist(a)] => fn(#RenderedDist(a))
|
||||||
|
| e => wrongInputsError(e)
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
|
||||||
|
let floatFromDist = (
|
||||||
|
distToFloatOp: ExpressionTypes.distToFloatOperation,
|
||||||
|
t: TypeSystem.samplingDist,
|
||||||
|
): result<node, string> =>
|
||||||
|
switch t {
|
||||||
|
| #SymbolicDist(s) =>
|
||||||
|
SymbolicDist.T.operate(distToFloatOp, s) |> E.R.bind(_, v => Ok(#SymbolicDist(#Float(v))))
|
||||||
|
| #RenderedDist(rs) => Shape.operate(distToFloatOp, rs) |> (v => Ok(#SymbolicDist(#Float(v))))
|
||||||
|
}
|
||||||
|
|
||||||
|
let verticalScaling = (scaleOp, rs, scaleBy) => {
|
||||||
|
// scaleBy has to be a single float, otherwise we'll return an error.
|
||||||
|
let fn = (secondary, main) => Operation.Scale.toFn(scaleOp, main, secondary)
|
||||||
|
let integralSumCacheFn = Operation.Scale.toIntegralSumCacheFn(scaleOp)
|
||||||
|
let integralCacheFn = Operation.Scale.toIntegralCacheFn(scaleOp)
|
||||||
|
Ok(
|
||||||
|
#RenderedDist(
|
||||||
|
Shape.T.mapY(
|
||||||
|
~integralSumCacheFn=integralSumCacheFn(scaleBy),
|
||||||
|
~integralCacheFn=integralCacheFn(scaleBy),
|
||||||
|
~fn=fn(scaleBy),
|
||||||
|
rs,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Multimodal = {
|
||||||
|
let getByNameResult = ExpressionTypes.ExpressionTree.Hash.getByNameResult
|
||||||
|
|
||||||
|
let _paramsToDistsAndWeights = (r: array<typedValue>) =>
|
||||||
|
switch r {
|
||||||
|
| [#Hash(r)] =>
|
||||||
|
let dists =
|
||||||
|
getByNameResult(r, "dists")
|
||||||
|
->E.R.bind(TypeSystem.TypedValue.toArray)
|
||||||
|
->E.R.bind(r => r |> E.A.fmap(TypeSystem.TypedValue.toDist) |> E.A.R.firstErrorOrOpen)
|
||||||
|
let weights =
|
||||||
|
getByNameResult(r, "weights")
|
||||||
|
->E.R.bind(TypeSystem.TypedValue.toArray)
|
||||||
|
->E.R.bind(r => r |> E.A.fmap(TypeSystem.TypedValue.toFloat) |> E.A.R.firstErrorOrOpen)
|
||||||
|
|
||||||
|
E.R.merge(dists, weights) |> E.R.fmap(((a, b)) =>
|
||||||
|
E.A.zipMaxLength(a, b) |> E.A.fmap(((a, b)) => (a |> E.O.toExn(""), b |> E.O.default(1.0)))
|
||||||
|
)
|
||||||
|
| _ => Error("Needs items")
|
||||||
|
}
|
||||||
|
let _runner: array<typedValue> => result<node, string> = r => {
|
||||||
|
let paramsToDistsAndWeights =
|
||||||
|
_paramsToDistsAndWeights(r) |> E.R.fmap(
|
||||||
|
E.A.fmap(((dist, weight)) =>
|
||||||
|
#FunctionCall("scaleMultiply", [dist, #SymbolicDist(#Float(weight))])
|
||||||
|
),
|
||||||
|
)
|
||||||
|
let pointwiseSum: result<node, string> =
|
||||||
|
paramsToDistsAndWeights->E.R.bind(E.R.errorIfCondition(E.A.isEmpty, "Needs one input"))
|
||||||
|
|> E.R.fmap(r =>
|
||||||
|
r
|
||||||
|
|> Js.Array.sliceFrom(1)
|
||||||
|
|> E.A.fold_left((acc, x) => #PointwiseCombination(#Add, acc, x), E.A.unsafe_get(r, 0))
|
||||||
|
)
|
||||||
|
pointwiseSum
|
||||||
|
}
|
||||||
|
|
||||||
|
let _function = Function.T.make(
|
||||||
|
~name="multimodal",
|
||||||
|
~outputType=#SamplingDistribution,
|
||||||
|
~inputTypes=[#Hash([("dists", #Array(#SamplingDistribution)), ("weights", #Array(#Float))])],
|
||||||
|
~run=_runner,
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let all = [
|
||||||
|
makeSymbolicFromTwoFloats("normal", SymbolicDist.Normal.make),
|
||||||
|
makeSymbolicFromTwoFloats("uniform", SymbolicDist.Uniform.make),
|
||||||
|
makeSymbolicFromTwoFloats("beta", SymbolicDist.Beta.make),
|
||||||
|
makeSymbolicFromTwoFloats("lognormal", SymbolicDist.Lognormal.make),
|
||||||
|
makeSymbolicFromTwoFloats("lognormalFromMeanAndStdDev", SymbolicDist.Lognormal.fromMeanAndStdev),
|
||||||
|
makeSymbolicFromOneFloat("exponential", SymbolicDist.Exponential.make),
|
||||||
|
Function.T.make(
|
||||||
|
~name="to",
|
||||||
|
~outputType=#SamplingDistribution,
|
||||||
|
~inputTypes=[#Float, #Float],
|
||||||
|
~run=x =>
|
||||||
|
switch x {
|
||||||
|
| [#Float(a), #Float(b)] => to_(a, b)
|
||||||
|
| e => wrongInputsError(e)
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
),
|
||||||
|
Function.T.make(
|
||||||
|
~name="triangular",
|
||||||
|
~outputType=#SamplingDistribution,
|
||||||
|
~inputTypes=[#Float, #Float, #Float],
|
||||||
|
~run=x =>
|
||||||
|
switch x {
|
||||||
|
| [#Float(a), #Float(b), #Float(c)] =>
|
||||||
|
SymbolicDist.Triangular.make(a, b, c) |> E.R.fmap(r => #SymbolicDist(r))
|
||||||
|
| e => wrongInputsError(e)
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
),
|
||||||
|
makeDistFloat("pdf", (dist, float) => floatFromDist(#Pdf(float), dist)),
|
||||||
|
makeDistFloat("inv", (dist, float) => floatFromDist(#Inv(float), dist)),
|
||||||
|
makeDistFloat("cdf", (dist, float) => floatFromDist(#Cdf(float), dist)),
|
||||||
|
makeDist("mean", dist => floatFromDist(#Mean, dist)),
|
||||||
|
makeDist("sample", dist => floatFromDist(#Sample, dist)),
|
||||||
|
Function.T.make(
|
||||||
|
~name="render",
|
||||||
|
~outputType=#RenderedDistribution,
|
||||||
|
~inputTypes=[#RenderedDistribution],
|
||||||
|
~run=x =>
|
||||||
|
switch x {
|
||||||
|
| [#RenderedDist(c)] => Ok(#RenderedDist(c))
|
||||||
|
| e => wrongInputsError(e)
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
),
|
||||||
|
Function.T.make(
|
||||||
|
~name="normalize",
|
||||||
|
~outputType=#SamplingDistribution,
|
||||||
|
~inputTypes=[#SamplingDistribution],
|
||||||
|
~run=x =>
|
||||||
|
switch x {
|
||||||
|
| [#SamplingDist(#SymbolicDist(c))] => Ok(#SymbolicDist(c))
|
||||||
|
| [#SamplingDist(#RenderedDist(c))] => Ok(#RenderedDist(Shape.T.normalize(c)))
|
||||||
|
| e => wrongInputsError(e)
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
),
|
||||||
|
makeRenderedDistFloat("scaleExp", (dist, float) => verticalScaling(#Exponentiate, dist, float)),
|
||||||
|
makeRenderedDistFloat("scaleMultiply", (dist, float) => verticalScaling(#Multiply, dist, float)),
|
||||||
|
makeRenderedDistFloat("scaleLog", (dist, float) => verticalScaling(#Log, dist, float)),
|
||||||
|
Multimodal._function,
|
||||||
|
]
|
|
@ -1,228 +0,0 @@
|
||||||
type node = ExpressionTypes.ExpressionTree.node;
|
|
||||||
let getFloat = ExpressionTypes.ExpressionTree.getFloat;
|
|
||||||
|
|
||||||
type samplingDist = [
|
|
||||||
| `SymbolicDist(SymbolicTypes.symbolicDist)
|
|
||||||
| `RenderedDist(DistTypes.shape)
|
|
||||||
];
|
|
||||||
|
|
||||||
type hashType = array((string, _type))
|
|
||||||
and _type = [
|
|
||||||
| `Float
|
|
||||||
| `SamplingDistribution
|
|
||||||
| `RenderedDistribution
|
|
||||||
| `Array(_type)
|
|
||||||
| `Hash(hashType)
|
|
||||||
];
|
|
||||||
|
|
||||||
type hashTypedValue = array((string, typedValue))
|
|
||||||
and typedValue = [
|
|
||||||
| `Float(float)
|
|
||||||
| `RenderedDist(DistTypes.shape)
|
|
||||||
| `SamplingDist(samplingDist)
|
|
||||||
| `Array(array(typedValue))
|
|
||||||
| `Hash(hashTypedValue)
|
|
||||||
];
|
|
||||||
|
|
||||||
type _function = {
|
|
||||||
name: string,
|
|
||||||
inputTypes: array(_type),
|
|
||||||
outputType: _type,
|
|
||||||
run: array(typedValue) => result(node, string),
|
|
||||||
shouldCoerceTypes: bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
type functions = array(_function);
|
|
||||||
type inputNodes = array(node);
|
|
||||||
|
|
||||||
module TypedValue = {
|
|
||||||
let rec toString: typedValue => string =
|
|
||||||
fun
|
|
||||||
| `SamplingDist(_) => "[sampling dist]"
|
|
||||||
| `RenderedDist(_) => "[rendered Shape]"
|
|
||||||
| `Float(f) => "Float: " ++ Js.Float.toString(f)
|
|
||||||
| `Array(a) =>
|
|
||||||
"[" ++ (a |> E.A.fmap(toString) |> Js.String.concatMany(_, ",")) ++ "]"
|
|
||||||
| `Hash(v) =>
|
|
||||||
"{"
|
|
||||||
++ (
|
|
||||||
v
|
|
||||||
|> E.A.fmap(((name, value)) => name ++ ":" ++ toString(value))
|
|
||||||
|> Js.String.concatMany(_, ",")
|
|
||||||
)
|
|
||||||
++ "}";
|
|
||||||
|
|
||||||
let rec fromNode = (node: node): result(typedValue, string) =>
|
|
||||||
switch (node) {
|
|
||||||
| `SymbolicDist(`Float(r)) => Ok(`Float(r))
|
|
||||||
| `SymbolicDist(s) => Ok(`SamplingDist(`SymbolicDist(s)))
|
|
||||||
| `RenderedDist(s) => Ok(`RenderedDist(s))
|
|
||||||
| `Array(r) =>
|
|
||||||
r
|
|
||||||
|> E.A.fmap(fromNode)
|
|
||||||
|> E.A.R.firstErrorOrOpen
|
|
||||||
|> E.R.fmap(r => `Array(r))
|
|
||||||
| `Hash(hash) =>
|
|
||||||
hash
|
|
||||||
|> E.A.fmap(((name, t)) => fromNode(t) |> E.R.fmap(r => (name, r)))
|
|
||||||
|> E.A.R.firstErrorOrOpen
|
|
||||||
|> E.R.fmap(r => `Hash(r))
|
|
||||||
| e => Error("Wrong type: " ++ ExpressionTreeBasic.toString(e))
|
|
||||||
};
|
|
||||||
|
|
||||||
// todo: Arrays and hashes
|
|
||||||
let rec fromNodeWithTypeCoercion = (evaluationParams, _type: _type, node) => {
|
|
||||||
switch (_type, node) {
|
|
||||||
| (`Float, _) =>
|
|
||||||
switch (getFloat(node)) {
|
|
||||||
| Some(a) => Ok(`Float(a))
|
|
||||||
| _ => Error("Type Error: Expected float.")
|
|
||||||
}
|
|
||||||
| (`SamplingDistribution, _) =>
|
|
||||||
PTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(
|
|
||||||
evaluationParams,
|
|
||||||
node,
|
|
||||||
)
|
|
||||||
|> E.R.bind(_, fromNode)
|
|
||||||
| (`RenderedDistribution, _) =>{
|
|
||||||
ExpressionTypes.ExpressionTree.Render.render(evaluationParams, node)
|
|
||||||
|> E.R.bind(_, fromNode);
|
|
||||||
}
|
|
||||||
| (`Array(_type), `Array(b)) =>
|
|
||||||
b
|
|
||||||
|> E.A.fmap(fromNodeWithTypeCoercion(evaluationParams, _type))
|
|
||||||
|> E.A.R.firstErrorOrOpen
|
|
||||||
|> E.R.fmap(r => `Array(r))
|
|
||||||
| (`Hash(named), `Hash(r)) =>
|
|
||||||
let keyValues =
|
|
||||||
named
|
|
||||||
|> E.A.fmap(((name, intendedType)) =>
|
|
||||||
(
|
|
||||||
name,
|
|
||||||
intendedType,
|
|
||||||
ExpressionTypes.ExpressionTree.Hash.getByName(r, name),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
let typedHash =
|
|
||||||
keyValues
|
|
||||||
|> E.A.fmap(((name, intendedType, optionNode)) =>
|
|
||||||
switch (optionNode) {
|
|
||||||
| Some(node) =>
|
|
||||||
fromNodeWithTypeCoercion(evaluationParams, intendedType, node)
|
|
||||||
|> E.R.fmap(node => (name, node))
|
|
||||||
| None => Error("Hash parameter not present in hash.")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|> E.A.R.firstErrorOrOpen
|
|
||||||
|> E.R.fmap(r => `Hash(r));
|
|
||||||
typedHash;
|
|
||||||
| _ => Error("fromNodeWithTypeCoercion error, sorry.")
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let toFloat: typedValue => result(float, string) =
|
|
||||||
fun
|
|
||||||
| `Float(x) => Ok(x)
|
|
||||||
| _ => Error("Not a float");
|
|
||||||
|
|
||||||
let toArray: typedValue => result(array('a), string) =
|
|
||||||
fun
|
|
||||||
| `Array(x) => Ok(x)
|
|
||||||
| _ => Error("Not an array");
|
|
||||||
|
|
||||||
let toNamed: typedValue => result(hashTypedValue, string) =
|
|
||||||
fun
|
|
||||||
| `Hash(x) => Ok(x)
|
|
||||||
| _ => Error("Not a named item");
|
|
||||||
|
|
||||||
let toDist: typedValue => result(node,string) =
|
|
||||||
fun
|
|
||||||
| `SamplingDist(`SymbolicDist(c)) => Ok(`SymbolicDist(c))
|
|
||||||
| `SamplingDist(`RenderedDist(c)) => Ok(`RenderedDist(c))
|
|
||||||
| `RenderedDist(c) => Ok(`RenderedDist(c))
|
|
||||||
| `Float(x) => Ok(`SymbolicDist(`Float(x)))
|
|
||||||
| x => Error("Cannot be converted into a distribution: " ++ toString(x));
|
|
||||||
};
|
|
||||||
|
|
||||||
module Function = {
|
|
||||||
type t = _function;
|
|
||||||
type ts = functions;
|
|
||||||
|
|
||||||
module T = {
|
|
||||||
let make =
|
|
||||||
(~name, ~inputTypes, ~outputType, ~run, ~shouldCoerceTypes=true, _): t => {
|
|
||||||
name,
|
|
||||||
inputTypes,
|
|
||||||
outputType,
|
|
||||||
run,
|
|
||||||
shouldCoerceTypes,
|
|
||||||
};
|
|
||||||
|
|
||||||
let _inputLengthCheck = (inputNodes: inputNodes, t: t) => {
|
|
||||||
let expectedLength = E.A.length(t.inputTypes);
|
|
||||||
let actualLength = E.A.length(inputNodes);
|
|
||||||
expectedLength == actualLength
|
|
||||||
? Ok(inputNodes)
|
|
||||||
: Error(
|
|
||||||
"Wrong number of inputs. Expected"
|
|
||||||
++ (expectedLength |> E.I.toString)
|
|
||||||
++ ". Got:"
|
|
||||||
++ (actualLength |> E.I.toString),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let _coerceInputNodes =
|
|
||||||
(evaluationParams, inputTypes, shouldCoerce, inputNodes) =>
|
|
||||||
Belt.Array.zip(inputTypes, inputNodes)
|
|
||||||
|> E.A.fmap(((def, input)) =>
|
|
||||||
shouldCoerce
|
|
||||||
? TypedValue.fromNodeWithTypeCoercion(
|
|
||||||
evaluationParams,
|
|
||||||
def,
|
|
||||||
input,
|
|
||||||
)
|
|
||||||
: TypedValue.fromNode(input)
|
|
||||||
)
|
|
||||||
|> E.A.R.firstErrorOrOpen;
|
|
||||||
|
|
||||||
let inputsToTypedValues =
|
|
||||||
(
|
|
||||||
evaluationParams: ExpressionTypes.ExpressionTree.evaluationParams,
|
|
||||||
inputNodes: inputNodes,
|
|
||||||
t: t,
|
|
||||||
) => {
|
|
||||||
_inputLengthCheck(inputNodes, t)
|
|
||||||
->E.R.bind(
|
|
||||||
_coerceInputNodes(
|
|
||||||
evaluationParams,
|
|
||||||
t.inputTypes,
|
|
||||||
t.shouldCoerceTypes,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let run =
|
|
||||||
(
|
|
||||||
evaluationParams: ExpressionTypes.ExpressionTree.evaluationParams,
|
|
||||||
inputNodes: inputNodes,
|
|
||||||
t: t,
|
|
||||||
) => {
|
|
||||||
inputsToTypedValues(evaluationParams, inputNodes, t)->E.R.bind(t.run)
|
|
||||||
|> (
|
|
||||||
fun
|
|
||||||
| Ok(i) => Ok(i)
|
|
||||||
| Error(r) => {
|
|
||||||
Error("Function " ++ t.name ++ " error: " ++ r);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module Ts = {
|
|
||||||
let findByName = (ts: ts, n: string) =>
|
|
||||||
ts |> Belt.Array.getBy(_, ({name}) => name == n);
|
|
||||||
|
|
||||||
let findByNameAndRun = (ts: ts, n: string, evaluationParams, inputTypes) =>
|
|
||||||
findByName(ts, n) |> E.O.fmap(T.run(evaluationParams, inputTypes));
|
|
||||||
};
|
|
||||||
};
|
|
204
packages/squiggle-lang/src/distPlus/typeSystem/TypeSystem.res
Normal file
204
packages/squiggle-lang/src/distPlus/typeSystem/TypeSystem.res
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
type node = ExpressionTypes.ExpressionTree.node
|
||||||
|
let getFloat = ExpressionTypes.ExpressionTree.getFloat
|
||||||
|
|
||||||
|
type samplingDist = [
|
||||||
|
| #SymbolicDist(SymbolicTypes.symbolicDist)
|
||||||
|
| #RenderedDist(DistTypes.shape)
|
||||||
|
]
|
||||||
|
|
||||||
|
type rec hashType = array<(string, _type)>
|
||||||
|
and _type = [
|
||||||
|
| #Float
|
||||||
|
| #SamplingDistribution
|
||||||
|
| #RenderedDistribution
|
||||||
|
| #Array(_type)
|
||||||
|
| #Hash(hashType)
|
||||||
|
]
|
||||||
|
|
||||||
|
type rec hashTypedValue = array<(string, typedValue)>
|
||||||
|
and typedValue = [
|
||||||
|
| #Float(float)
|
||||||
|
| #RenderedDist(DistTypes.shape)
|
||||||
|
| #SamplingDist(samplingDist)
|
||||||
|
| #Array(array<typedValue>)
|
||||||
|
| #Hash(hashTypedValue)
|
||||||
|
]
|
||||||
|
|
||||||
|
type _function = {
|
||||||
|
name: string,
|
||||||
|
inputTypes: array<_type>,
|
||||||
|
outputType: _type,
|
||||||
|
run: array<typedValue> => result<node, string>,
|
||||||
|
shouldCoerceTypes: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
type functions = array<_function>
|
||||||
|
type inputNodes = array<node>
|
||||||
|
|
||||||
|
module TypedValue = {
|
||||||
|
let rec toString: typedValue => string = x =>
|
||||||
|
switch x {
|
||||||
|
| #SamplingDist(_) => "[sampling dist]"
|
||||||
|
| #RenderedDist(_) => "[rendered Shape]"
|
||||||
|
| #Float(f) => "Float: " ++ Js.Float.toString(f)
|
||||||
|
| #Array(a) => "[" ++ ((a |> E.A.fmap(toString) |> Js.String.concatMany(_, ",")) ++ "]")
|
||||||
|
| #Hash(v) =>
|
||||||
|
"{" ++
|
||||||
|
((v
|
||||||
|
|> E.A.fmap(((name, value)) => name ++ (":" ++ toString(value)))
|
||||||
|
|> Js.String.concatMany(_, ",")) ++
|
||||||
|
"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
let rec fromNode = (node: node): result<typedValue, string> =>
|
||||||
|
switch node {
|
||||||
|
| #SymbolicDist(#Float(r)) => Ok(#Float(r))
|
||||||
|
| #SymbolicDist(s) => Ok(#SamplingDist(#SymbolicDist(s)))
|
||||||
|
| #RenderedDist(s) => Ok(#RenderedDist(s))
|
||||||
|
| #Array(r) => r |> E.A.fmap(fromNode) |> E.A.R.firstErrorOrOpen |> E.R.fmap(r => #Array(r))
|
||||||
|
| #Hash(hash) =>
|
||||||
|
hash
|
||||||
|
|> E.A.fmap(((name, t)) => fromNode(t) |> E.R.fmap(r => (name, r)))
|
||||||
|
|> E.A.R.firstErrorOrOpen
|
||||||
|
|> E.R.fmap(r => #Hash(r))
|
||||||
|
| e => Error("Wrong type: " ++ ExpressionTreeBasic.toString(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: Arrays and hashes
|
||||||
|
let rec fromNodeWithTypeCoercion = (evaluationParams, _type: _type, node) =>
|
||||||
|
switch (_type, node) {
|
||||||
|
| (#Float, _) =>
|
||||||
|
switch getFloat(node) {
|
||||||
|
| Some(a) => Ok(#Float(a))
|
||||||
|
| _ => Error("Type Error: Expected float.")
|
||||||
|
}
|
||||||
|
| (#SamplingDistribution, _) =>
|
||||||
|
PTypes.SamplingDistribution.renderIfIsNotSamplingDistribution(
|
||||||
|
evaluationParams,
|
||||||
|
node,
|
||||||
|
) |> E.R.bind(_, fromNode)
|
||||||
|
| (#RenderedDistribution, _) =>
|
||||||
|
ExpressionTypes.ExpressionTree.Render.render(evaluationParams, node) |> E.R.bind(_, fromNode)
|
||||||
|
| (#Array(_type), #Array(b)) =>
|
||||||
|
b
|
||||||
|
|> E.A.fmap(fromNodeWithTypeCoercion(evaluationParams, _type))
|
||||||
|
|> E.A.R.firstErrorOrOpen
|
||||||
|
|> E.R.fmap(r => #Array(r))
|
||||||
|
| (#Hash(named), #Hash(r)) =>
|
||||||
|
let keyValues =
|
||||||
|
named |> E.A.fmap(((name, intendedType)) => (
|
||||||
|
name,
|
||||||
|
intendedType,
|
||||||
|
ExpressionTypes.ExpressionTree.Hash.getByName(r, name),
|
||||||
|
))
|
||||||
|
let typedHash =
|
||||||
|
keyValues
|
||||||
|
|> E.A.fmap(((name, intendedType, optionNode)) =>
|
||||||
|
switch optionNode {
|
||||||
|
| Some(node) =>
|
||||||
|
fromNodeWithTypeCoercion(evaluationParams, intendedType, node) |> E.R.fmap(node => (
|
||||||
|
name,
|
||||||
|
node,
|
||||||
|
))
|
||||||
|
| None => Error("Hash parameter not present in hash.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|> E.A.R.firstErrorOrOpen
|
||||||
|
|> E.R.fmap(r => #Hash(r))
|
||||||
|
typedHash
|
||||||
|
| _ => Error("fromNodeWithTypeCoercion error, sorry.")
|
||||||
|
}
|
||||||
|
|
||||||
|
let toFloat: typedValue => result<float, string> = x =>
|
||||||
|
switch x {
|
||||||
|
| #Float(x) => Ok(x)
|
||||||
|
| _ => Error("Not a float")
|
||||||
|
}
|
||||||
|
|
||||||
|
let toArray: typedValue => result<array<'a>, string> = x =>
|
||||||
|
switch x {
|
||||||
|
| #Array(x) => Ok(x)
|
||||||
|
| _ => Error("Not an array")
|
||||||
|
}
|
||||||
|
|
||||||
|
let toNamed: typedValue => result<hashTypedValue, string> = x =>
|
||||||
|
switch x {
|
||||||
|
| #Hash(x) => Ok(x)
|
||||||
|
| _ => Error("Not a named item")
|
||||||
|
}
|
||||||
|
|
||||||
|
let toDist: typedValue => result<node, string> = x =>
|
||||||
|
switch x {
|
||||||
|
| #SamplingDist(#SymbolicDist(c)) => Ok(#SymbolicDist(c))
|
||||||
|
| #SamplingDist(#RenderedDist(c)) => Ok(#RenderedDist(c))
|
||||||
|
| #RenderedDist(c) => Ok(#RenderedDist(c))
|
||||||
|
| #Float(x) => Ok(#SymbolicDist(#Float(x)))
|
||||||
|
| x => Error("Cannot be converted into a distribution: " ++ toString(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module Function = {
|
||||||
|
type t = _function
|
||||||
|
type ts = functions
|
||||||
|
|
||||||
|
module T = {
|
||||||
|
let make = (~name, ~inputTypes, ~outputType, ~run, ~shouldCoerceTypes=true, _): t => {
|
||||||
|
name: name,
|
||||||
|
inputTypes: inputTypes,
|
||||||
|
outputType: outputType,
|
||||||
|
run: run,
|
||||||
|
shouldCoerceTypes: shouldCoerceTypes,
|
||||||
|
}
|
||||||
|
|
||||||
|
let _inputLengthCheck = (inputNodes: inputNodes, t: t) => {
|
||||||
|
let expectedLength = E.A.length(t.inputTypes)
|
||||||
|
let actualLength = E.A.length(inputNodes)
|
||||||
|
expectedLength == actualLength
|
||||||
|
? Ok(inputNodes)
|
||||||
|
: Error(
|
||||||
|
"Wrong number of inputs. Expected" ++
|
||||||
|
((expectedLength |> E.I.toString) ++
|
||||||
|
(". Got:" ++ (actualLength |> E.I.toString))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let _coerceInputNodes = (evaluationParams, inputTypes, shouldCoerce, inputNodes) =>
|
||||||
|
Belt.Array.zip(inputTypes, inputNodes)
|
||||||
|
|> E.A.fmap(((def, input)) =>
|
||||||
|
shouldCoerce
|
||||||
|
? TypedValue.fromNodeWithTypeCoercion(evaluationParams, def, input)
|
||||||
|
: TypedValue.fromNode(input)
|
||||||
|
)
|
||||||
|
|> E.A.R.firstErrorOrOpen
|
||||||
|
|
||||||
|
let inputsToTypedValues = (
|
||||||
|
evaluationParams: ExpressionTypes.ExpressionTree.evaluationParams,
|
||||||
|
inputNodes: inputNodes,
|
||||||
|
t: t,
|
||||||
|
) =>
|
||||||
|
_inputLengthCheck(inputNodes, t)->E.R.bind(
|
||||||
|
_coerceInputNodes(evaluationParams, t.inputTypes, t.shouldCoerceTypes),
|
||||||
|
)
|
||||||
|
|
||||||
|
let run = (
|
||||||
|
evaluationParams: ExpressionTypes.ExpressionTree.evaluationParams,
|
||||||
|
inputNodes: inputNodes,
|
||||||
|
t: t,
|
||||||
|
) =>
|
||||||
|
inputsToTypedValues(evaluationParams, inputNodes, t)->E.R.bind(t.run)
|
||||||
|
|> (
|
||||||
|
x =>
|
||||||
|
switch x {
|
||||||
|
| Ok(i) => Ok(i)
|
||||||
|
| Error(r) => Error("Function " ++ (t.name ++ (" error: " ++ r)))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Ts = {
|
||||||
|
let findByName = (ts: ts, n: string) => ts |> Belt.Array.getBy(_, ({name}) => name == n)
|
||||||
|
|
||||||
|
let findByNameAndRun = (ts: ts, n: string, evaluationParams, inputTypes) =>
|
||||||
|
findByName(ts, n) |> E.O.fmap(T.run(evaluationParams, inputTypes))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
@module("jStat") @scope("normal") external mean: (float, float) => float = "mean"
|
|
||||||
|
|
||||||
let foo = mean;
|
|
Loading…
Reference in New Issue
Block a user