Compare commits

..

No commits in common. "develop" and "drop-bisect-ppx" have entirely different histories.

55 changed files with 738 additions and 949 deletions

View File

@ -24,7 +24,7 @@ export const Alert: React.FC<{
children,
}) => {
return (
<div className={clsx("rounded-md p-4", backgroundColor)} role="status">
<div className={clsx("rounded-md p-4", backgroundColor)}>
<div className="flex">
<Icon
className={clsx("h-5 w-5 flex-shrink-0", iconColor)}

View File

@ -55,7 +55,10 @@ export const CodeEditor: FC<CodeEditorProps> = ({
editorProps={{
$blockScrolling: true,
}}
setOptions={{}}
setOptions={{
enableBasicAutocompletion: false,
enableLiveAutocompletion: false,
}}
commands={[
{
name: "submit",

View File

@ -1,10 +1,5 @@
import * as React from "react";
import {
SqValue,
environment,
SqProject,
defaultEnvironment,
} from "@quri/squiggle-lang";
import { SqValue, environment, SqProject } from "@quri/squiggle-lang";
import { useSquiggle } from "../lib/hooks";
import { SquiggleViewer } from "./SquiggleViewer";
import { JsImports } from "../lib/jsImports";
@ -71,6 +66,7 @@ type ProjectExecutionProps = {
};
const defaultOnChange = () => {};
const defaultImports: JsImports = {};
const defaultContinues: string[] = [];
export const splitSquiggleChartSettings = (props: SquiggleChartProps) => {
const {
@ -124,15 +120,24 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
width,
height = 200,
enableLocalSettings = false,
continues,
project,
environment,
continues = defaultContinues,
} = props;
const p = React.useMemo(() => {
if (props.project) {
return props.project;
} else {
const p = SqProject.create();
if (props.environment) {
p.setEnvironment(props.environment);
}
return p;
}
}, [props.project, props.environment]);
const resultAndBindings = useSquiggle({
environment,
continues,
project,
project: p,
code,
jsImports,
onChange,
@ -148,9 +153,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
height={height}
distributionPlotSettings={distributionPlotSettings}
chartSettings={chartSettings}
environment={
project ? project.getEnvironment() : environment ?? defaultEnvironment
}
environment={p.getEnvironment()}
enableLocalSettings={enableLocalSettings}
/>
);

View File

@ -54,13 +54,17 @@ export const SquiggleEditor: React.FC<SquiggleEditorProps> = (props) => {
width,
height = 200,
enableLocalSettings = false,
continues,
project,
} = props;
const project = React.useMemo(() => {
const p = SqProject.create();
if (environment) {
p.setEnvironment(environment);
}
return p;
}, [environment]);
const resultAndBindings = useSquiggle({
environment,
continues,
code,
project,
jsImports,

View File

@ -251,8 +251,6 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
onSettingsChange,
showEditor = true,
showShareButton = false,
continues,
project,
}) => {
const [code, setCode] = useMaybeControlledValue({
value: controlledCode,
@ -307,9 +305,15 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
executionId,
} = useRunnerState(code);
const project = React.useMemo(() => {
const p = SqProject.create();
if (environment) {
p.setEnvironment(environment);
}
return p;
}, [environment]);
const resultAndBindings = useSquiggle({
environment,
continues,
code: renderedCode,
project,
jsImports: imports,

View File

@ -45,7 +45,7 @@ export const VariableBox: React.FC<VariableBoxProps> = ({
: location.path.items[location.path.items.length - 1];
return (
<div role={isTopLevel ? "status" : undefined}>
<div>
<header className="inline-flex space-x-1">
<Tooltip text={heading}>
<span

View File

@ -4,18 +4,16 @@ import {
SqProject,
SqRecord,
SqValue,
environment,
} from "@quri/squiggle-lang";
import { useEffect, useMemo } from "react";
import { JsImports, jsImportsToSquiggleCode } from "../jsImports";
import * as uuid from "uuid";
type SquiggleArgs = {
environment?: environment;
code: string;
executionId?: number;
jsImports?: JsImports;
project?: SqProject;
project: SqProject;
continues?: string[];
onChange?: (expr: SqValue | undefined, sourceName: string) => void;
};
@ -29,25 +27,15 @@ const importSourceName = (sourceName: string) => "imports-" + sourceName;
const defaultContinues = [];
export const useSquiggle = (args: SquiggleArgs): ResultAndBindings => {
const project = useMemo(() => {
if (args.project) {
return args.project;
} else {
const p = SqProject.create();
if (args.environment) {
p.setEnvironment(args.environment);
}
return p;
}
}, [args.project, args.environment]);
const sourceName = useMemo(() => uuid.v4(), []);
const env = project.getEnvironment();
const env = args.project.getEnvironment();
const continues = args.continues || defaultContinues;
const result = useMemo(
() => {
const project = args.project;
project.setSource(sourceName, args.code);
let fullContinues = continues;
if (args.jsImports && Object.keys(args.jsImports).length) {
@ -71,7 +59,7 @@ export const useSquiggle = (args: SquiggleArgs): ResultAndBindings => {
args.executionId,
sourceName,
continues,
project,
args.project,
env,
]
);
@ -87,11 +75,11 @@ export const useSquiggle = (args: SquiggleArgs): ResultAndBindings => {
useEffect(() => {
return () => {
project.removeSource(sourceName);
if (project.getSource(importSourceName(sourceName)))
project.removeSource(importSourceName(sourceName));
args.project.removeSource(sourceName);
if (args.project.getSource(importSourceName(sourceName)))
args.project.removeSource(importSourceName(sourceName));
};
}, [project, sourceName]);
}, [args.project, sourceName]);
return result;
};

View File

@ -1,14 +1,9 @@
import { render, screen } from "@testing-library/react";
import { render } from "@testing-library/react";
import React from "react";
import "@testing-library/jest-dom";
import {
SquiggleChart,
SquiggleEditor,
SquigglePlayground,
} from "../src/index";
import { SqProject } from "@quri/squiggle-lang";
import { SquiggleChart } from "../src/index";
test("Chart logs nothing on render", async () => {
test("Logs nothing on render", async () => {
const { unmount } = render(<SquiggleChart code={"normal(0, 1)"} />);
unmount();
@ -16,38 +11,3 @@ test("Chart logs nothing on render", async () => {
expect(console.warn).not.toBeCalled();
expect(console.error).not.toBeCalled();
});
test("Editor logs nothing on render", async () => {
const { unmount } = render(<SquiggleEditor code={"normal(0, 1)"} />);
unmount();
expect(console.log).not.toBeCalled();
expect(console.warn).not.toBeCalled();
expect(console.error).not.toBeCalled();
});
test("Project dependencies work in editors", async () => {
const project = SqProject.create();
render(<SquiggleEditor code={"x = 1"} project={project} />);
const source = project.getSourceIds()[0];
const { container } = render(
<SquiggleEditor code={"x + 1"} project={project} continues={[source]} />
);
expect(container).toHaveTextContent("2");
});
test("Project dependencies work in playgrounds", async () => {
const project = SqProject.create();
project.setSource("depend", "x = 1");
render(
<SquigglePlayground
code={"x + 1"}
project={project}
continues={["depend"]}
/>
);
// We must await here because SquigglePlayground loads results asynchronously
expect(await screen.findByRole("status")).toHaveTextContent("2");
});

View File

@ -3,7 +3,7 @@ lib
*.bs.js
*.gen.tsx
.nyc_output/
coverage/
_coverage/
.cache/
Reducer_Peggy_GeneratedParser.js
ReducerProject_IncludeParser.js

View File

@ -32,10 +32,7 @@ describe("dotSubtract", () => {
*/
Skip.test("mean of normal minus exponential (property)", () => {
assert_(
property2(
float_(),
floatRange(1e-5, 1e5),
(mean, rate) => {
property2(float_(), floatRange(1e-5, 1e5), (mean, rate) => {
// We limit ourselves to stdev=1 so that the integral is trivial
let dotDifference = DistributionOperation.Constructors.pointwiseSubtract(
~env,
@ -53,8 +50,7 @@ describe("dotSubtract", () => {
| Ok(meanValue) => abs_float(meanValue -. meanAnalytical) /. abs_float(meanValue) < 1e-2 // 1% relative error
| Error(err) => err === DistributionTypes.OperationError(DivisionByZeroError)
}
},
),
}),
)
pass
})

View File

@ -40,9 +40,7 @@ let algebraicPower = algebraicPower(~env)
describe("(Algebraic) addition of distributions", () => {
describe("mean", () => {
test(
"normal(mean=5) + normal(mean=20)",
() => {
test("normal(mean=5) + normal(mean=20)", () => {
normalDist5
->algebraicAdd(normalDist20)
->E.R2.fmap(DistributionTypes.Constructors.UsingDists.mean)
@ -51,12 +49,9 @@ describe("(Algebraic) addition of distributions", () => {
->E.R.toExn("Expected float", _)
->expect
->toBe(Some(2.5e1))
},
)
})
test(
"uniform(low=9, high=10) + beta(alpha=2, beta=5)",
() => {
test("uniform(low=9, high=10) + beta(alpha=2, beta=5)", () => {
// let uniformMean = (9.0 +. 10.0) /. 2.0
// let betaMean = 1.0 /. (1.0 +. 5.0 /. 2.0)
let received =
@ -72,11 +67,8 @@ describe("(Algebraic) addition of distributions", () => {
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.786831807237022, ~digits=1) // (uniformMean +. betaMean)
}
},
)
test(
"beta(alpha=2, beta=5) + uniform(low=9, high=10)",
() => {
})
test("beta(alpha=2, beta=5) + uniform(low=9, high=10)", () => {
// let uniformMean = (9.0 +. 10.0) /. 2.0
// let betaMean = 1.0 /. (1.0 +. 5.0 /. 2.0)
let received =
@ -92,8 +84,7 @@ describe("(Algebraic) addition of distributions", () => {
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.784290207736126, ~digits=1) // (uniformMean +. betaMean)
}
},
)
})
})
describe("pdf", () => {
// TEST IS WRONG. SEE STDEV ADDITION EXPRESSION.
@ -131,9 +122,7 @@ describe("(Algebraic) addition of distributions", () => {
}
},
)
test(
"(normal(mean=10) + normal(mean=10)).pdf(1.9e1)",
() => {
test("(normal(mean=10) + normal(mean=10)).pdf(1.9e1)", () => {
let received =
normalDist20
->Ok
@ -161,11 +150,8 @@ describe("(Algebraic) addition of distributions", () => {
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=1)
}
}
},
)
test(
"(uniform(low=9, high=10) + beta(alpha=2, beta=5)).pdf(10)",
() => {
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).pdf(10)", () => {
let received =
uniformDist
->algebraicAdd(betaDist)
@ -180,11 +166,8 @@ describe("(Algebraic) addition of distributions", () => {
// This value was calculated by a python script
| Some(x) => x->expect->toBeSoCloseTo(0.979023, ~digits=0)
}
},
)
test(
"(beta(alpha=2, beta=5) + uniform(low=9, high=10)).pdf(10)",
() => {
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).pdf(10)", () => {
let received =
betaDist
->algebraicAdd(uniformDist)
@ -197,14 +180,10 @@ describe("(Algebraic) addition of distributions", () => {
// This is nondeterministic.
| Some(x) => x->expect->toBeSoCloseTo(0.979023, ~digits=0)
}
},
)
})
})
describe("cdf", () => {
testAll(
"(normal(mean=5) + normal(mean=5)).cdf (imprecise)",
list{6e0, 8e0, 1e1, 1.2e1},
x => {
testAll("(normal(mean=5) + normal(mean=5)).cdf (imprecise)", list{6e0, 8e0, 1e1, 1.2e1}, x => {
let received =
normalDist10
->Ok
@ -233,11 +212,8 @@ describe("(Algebraic) addition of distributions", () => {
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=0)
}
}
},
)
test(
"(normal(mean=10) + normal(mean=10)).cdf(1.25e1)",
() => {
})
test("(normal(mean=10) + normal(mean=10)).cdf(1.25e1)", () => {
let received =
normalDist20
->Ok
@ -265,11 +241,8 @@ describe("(Algebraic) addition of distributions", () => {
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=2)
}
}
},
)
test(
"(uniform(low=9, high=10) + beta(alpha=2, beta=5)).cdf(10)",
() => {
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).cdf(10)", () => {
let received =
uniformDist
->algebraicAdd(betaDist)
@ -283,11 +256,8 @@ describe("(Algebraic) addition of distributions", () => {
// The value was calculated externally using a python script
| Some(x) => x->expect->toBeSoCloseTo(0.71148, ~digits=1)
}
},
)
test(
"(beta(alpha=2, beta=5) + uniform(low=9, high=10)).cdf(10)",
() => {
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).cdf(10)", () => {
let received =
betaDist
->algebraicAdd(uniformDist)
@ -301,15 +271,11 @@ describe("(Algebraic) addition of distributions", () => {
// The value was calculated externally using a python script
| Some(x) => x->expect->toBeSoCloseTo(0.71148, ~digits=1)
}
},
)
})
})
describe("inv", () => {
testAll(
"(normal(mean=5) + normal(mean=5)).inv (imprecise)",
list{5e-2, 4.2e-3, 9e-3},
x => {
testAll("(normal(mean=5) + normal(mean=5)).inv (imprecise)", list{5e-2, 4.2e-3, 9e-3}, x => {
let received =
normalDist10
->Ok
@ -338,11 +304,8 @@ describe("(Algebraic) addition of distributions", () => {
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=-1)
}
}
},
)
test(
"(normal(mean=10) + normal(mean=10)).inv(1e-1)",
() => {
})
test("(normal(mean=10) + normal(mean=10)).inv(1e-1)", () => {
let received =
normalDist20
->Ok
@ -370,11 +333,8 @@ describe("(Algebraic) addition of distributions", () => {
| Some(y) => x->expect->toBeSoCloseTo(y, ~digits=-1)
}
}
},
)
test(
"(uniform(low=9, high=10) + beta(alpha=2, beta=5)).inv(2e-2)",
() => {
})
test("(uniform(low=9, high=10) + beta(alpha=2, beta=5)).inv(2e-2)", () => {
let received =
uniformDist
->algebraicAdd(betaDist)
@ -388,11 +348,8 @@ describe("(Algebraic) addition of distributions", () => {
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.179319623146968, ~digits=0)
}
},
)
test(
"(beta(alpha=2, beta=5) + uniform(low=9, high=10)).inv(2e-2)",
() => {
})
test("(beta(alpha=2, beta=5) + uniform(low=9, high=10)).inv(2e-2)", () => {
let received =
betaDist
->algebraicAdd(uniformDist)
@ -406,7 +363,6 @@ describe("(Algebraic) addition of distributions", () => {
// sometimes it works with ~digits=2.
| Some(x) => x->expect->toBeSoCloseTo(9.190872365862756, ~digits=0)
}
},
)
})
})
})

View File

@ -87,22 +87,14 @@ describe("Means are invariant", () => {
let testAddInvariant = (t1, t2) =>
E.R.liftM2(testAdditionMean, t1, t2)->E.R.toExn("Means were not invariant", _)
testAll(
"with two of the same distribution",
distributions,
dist => {
testAll("with two of the same distribution", distributions, dist => {
testAddInvariant(dist, dist)
},
)
})
testAll(
"with two different distributions",
pairsOfDifferentDistributions,
dists => {
testAll("with two different distributions", pairsOfDifferentDistributions, dists => {
let (dist1, dist2) = dists
testAddInvariant(dist1, dist2)
},
)
})
testAll(
"with two different distributions in swapped order",
@ -124,22 +116,14 @@ describe("Means are invariant", () => {
let testSubtractInvariant = (t1, t2) =>
E.R.liftM2(testSubtractionMean, t1, t2)->E.R.toExn("Means were not invariant", _)
testAll(
"with two of the same distribution",
distributions,
dist => {
testAll("with two of the same distribution", distributions, dist => {
testSubtractInvariant(dist, dist)
},
)
})
testAll(
"with two different distributions",
pairsOfDifferentDistributions,
dists => {
testAll("with two different distributions", pairsOfDifferentDistributions, dists => {
let (dist1, dist2) = dists
testSubtractInvariant(dist1, dist2)
},
)
})
testAll(
"with two different distributions in swapped order",
@ -161,22 +145,14 @@ describe("Means are invariant", () => {
let testMultiplicationInvariant = (t1, t2) =>
E.R.liftM2(testMultiplicationMean, t1, t2)->E.R.toExn("Means were not invariant", _)
testAll(
"with two of the same distribution",
distributions,
dist => {
testAll("with two of the same distribution", distributions, dist => {
testMultiplicationInvariant(dist, dist)
},
)
})
testAll(
"with two different distributions",
pairsOfDifferentDistributions,
dists => {
testAll("with two different distributions", pairsOfDifferentDistributions, dists => {
let (dist1, dist2) = dists
testMultiplicationInvariant(dist1, dist2)
},
)
})
testAll(
"with two different distributions in swapped order",

View File

@ -17,9 +17,10 @@ describe("klDivergence: continuous -> continuous -> float", () => {
let answer =
uniformMakeR(lowAnswer, highAnswer)->E.R2.errMap(s => DistributionTypes.ArgumentError(s))
let prediction =
uniformMakeR(lowPrediction, highPrediction)->E.R2.errMap(
s => DistributionTypes.ArgumentError(s),
)
uniformMakeR(
lowPrediction,
highPrediction,
)->E.R2.errMap(s => DistributionTypes.ArgumentError(s))
// integral along the support of the answer of answer.pdf(x) times log of prediction.pdf(x) divided by answer.pdf(x) dx
let analyticalKl = Js.Math.log((highPrediction -. lowPrediction) /. (highAnswer -. lowAnswer))
let kl = E.R.liftJoin2(klDivergence, prediction, answer)
@ -182,9 +183,9 @@ describe("combineAlongSupportOfSecondArgument0", () => {
let answer =
uniformMakeR(lowAnswer, highAnswer)->E.R2.errMap(s => DistributionTypes.ArgumentError(s))
let prediction =
uniformMakeR(lowPrediction, highPrediction)->E.R2.errMap(
s => DistributionTypes.ArgumentError(s),
)
uniformMakeR(lowPrediction, highPrediction)->E.R2.errMap(s => DistributionTypes.ArgumentError(
s,
))
let answerWrapped = E.R.fmap(a => run(FromDist(#ToDist(ToPointSet), a)), answer)
let predictionWrapped = E.R.fmap(a => run(FromDist(#ToDist(ToPointSet), a)), prediction)

View File

@ -3,7 +3,7 @@ open Expect
open TestHelpers
// TODO: use Normal.make (but preferably after teh new validation dispatch is in)
let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean, stdev}))
let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean: mean, stdev: stdev}))
describe("(Symbolic) normalize", () => {
testAll("has no impact on normal distributions", list{-1e8, -1e-2, 0.0, 1e-4, 1e16}, mean => {
@ -47,7 +47,10 @@ describe("(Symbolic) mean", () => {
tup => {
let (low, medium, high) = tup
let meanValue = run(
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Triangular({low, medium, high}))),
FromDist(
#ToFloat(#Mean),
DistributionTypes.Symbolic(#Triangular({low: low, medium: medium, high: high})),
),
)
meanValue->unpackFloat->expect->toBeCloseTo((low +. medium +. high) /. 3.0) // https://www.statology.org/triangular-distribution/
},
@ -60,7 +63,7 @@ describe("(Symbolic) mean", () => {
tup => {
let (alpha, beta) = tup
let meanValue = run(
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Beta({alpha, beta}))),
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Beta({alpha: alpha, beta: beta}))),
)
meanValue->unpackFloat->expect->toBeCloseTo(1.0 /. (1.0 +. beta /. alpha)) // https://en.wikipedia.org/wiki/Beta_distribution#Mean
},
@ -81,8 +84,8 @@ describe("(Symbolic) mean", () => {
let (mean, stdev) = tup
let betaDistribution = SymbolicDist.Beta.fromMeanAndStdev(mean, stdev)
let meanValue =
betaDistribution->E.R2.fmap(
d => run(FromDist(#ToFloat(#Mean), d->DistributionTypes.Symbolic)),
betaDistribution->E.R2.fmap(d =>
run(FromDist(#ToFloat(#Mean), d->DistributionTypes.Symbolic))
)
switch meanValue {
| Ok(value) => value->unpackFloat->expect->toBeCloseTo(mean)
@ -97,7 +100,7 @@ describe("(Symbolic) mean", () => {
tup => {
let (mu, sigma) = tup
let meanValue = run(
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Lognormal({mu, sigma}))),
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Lognormal({mu: mu, sigma: sigma}))),
)
meanValue->unpackFloat->expect->toBeCloseTo(Js.Math.exp(mu +. sigma ** 2.0 /. 2.0)) // https://brilliant.org/wiki/log-normal-distribution/
},
@ -109,7 +112,7 @@ describe("(Symbolic) mean", () => {
tup => {
let (low, high) = tup
let meanValue = run(
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Uniform({low, high}))),
FromDist(#ToFloat(#Mean), DistributionTypes.Symbolic(#Uniform({low: low, high: high}))),
)
meanValue->unpackFloat->expect->toBeCloseTo((low +. high) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments
},

View File

@ -33,18 +33,12 @@ describe("Bindings", () => {
let value2 = Reducer_T.IEvNumber(5.)
let extendedBindings = bindings->Bindings.extend->Bindings.set("value", value2)
test(
"get on extended",
() => {
test("get on extended", () => {
expect(extendedBindings->Bindings.get("value")) == Some(value2)
},
)
})
test(
"get on original",
() => {
test("get on original", () => {
expect(bindings->Bindings.get("value")) == Some(value)
},
)
})
})
})

View File

@ -40,23 +40,14 @@ describe("Namespace", () => {
let nsMerged = Namespace.mergeMany([ns, ns1, ns2])
test(
"merge many 1",
() => {
test("merge many 1", () => {
expect(nsMerged->Namespace.get("x1")) == Some(x1)
},
)
test(
"merge many 2",
() => {
})
test("merge many 2", () => {
expect(nsMerged->Namespace.get("x4")) == Some(x4)
},
)
test(
"merge many 3",
() => {
})
test("merge many 3", () => {
expect(nsMerged->Namespace.get("value")) == Some(value)
},
)
})
})
})

View File

@ -75,9 +75,7 @@ describe("Peggy to Expression", () => {
testToExpression("false ? 1 : 0", "false ? (1) : (0)", ~v="0", ())
testToExpression("true ? 1 : false ? 2 : 0", "true ? (1) : (false ? (2) : (0))", ~v="1", ()) // nested ternary
testToExpression("false ? 1 : false ? 2 : 0", "false ? (1) : (false ? (2) : (0))", ~v="0", ()) // nested ternary
describe(
"ternary bindings",
() => {
describe("ternary bindings", () => {
testToExpression(
// expression binding
"f(a) = a > 5 ? 1 : 0; f(6)",
@ -99,8 +97,7 @@ describe("Peggy to Expression", () => {
~v="6",
(),
)
},
)
})
})
describe("if then else", () => {

View File

@ -22,7 +22,7 @@ let expectEvalError = (code: string) =>
Expression.BackCompatible.evaluateString(code)
->Reducer_Value.toStringResult
->expect
->toMatch("Error\\(")
->toMatch("Error\(")
let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer))
let testDescriptionParseToBe = (desc, expr, answer) =>

View File

@ -37,16 +37,14 @@ describe("eval", () => {
test("index", () => expectEvalToBe("r = {a: 1}; r.a", "Ok(1)"))
test("index", () => expectEvalToBe("r = {a: 1}; r.b", "Error(Record property not found: b)"))
testEvalError("{a: 1}.b") // invalid syntax
test(
"always the same property ending",
() =>
test("always the same property ending", () =>
expectEvalToBe(
`{
a: 1,
b: 2,
}`,
"Ok({a: 1,b: 2})",
),
)
)
})

View File

@ -11,9 +11,7 @@ describe("ReducerProject Tutorial", () => {
/*
Case "Running a single source".
*/
test(
"run",
() => {
test("run", () => {
/* Let's start with running a single source and getting Result as well as the Bindings
First you need to create a project. A project is a collection of sources.
Project takes care of the dependencies between the sources, correct compilation and run order.
@ -53,12 +51,9 @@ Case "Running a single source".
(result->Reducer_Value.toStringResult, bindings->Reducer_Value.toStringRecord)->expect ==
("Ok(3)", "{}")
/* You've got 3 with empty bindings. */
},
)
})
test(
"run summary",
() => {
test("run summary", () => {
let project = Project.createProject()
project->Project.setSource("main", "1 + 2")
project->Project.runAll
@ -69,12 +64,9 @@ Case "Running a single source".
result->Reducer_Value.toStringResult,
bindings->Reducer_T.IEvRecord->Reducer_Value.toString,
)->expect == ("Ok(3)", "{}")
},
)
})
test(
"run with an environment",
() => {
test("run with an environment", () => {
/* Running the source code like above allows you to set a custom environment */
let project = Project.createProject()
@ -86,19 +78,15 @@ Case "Running a single source".
let result = project->Project.getResult("main")
let _bindings = project->Project.getBindings("main")
result->Reducer_Value.toStringResult->expect == "Ok(3)"
},
)
})
test(
"shortcut",
() => {
test("shortcut", () => {
/* If you are running single source without includes and you don't need a custom environment, you can use the shortcut. */
/* Examples above was to prepare you for the multi source tutorial. */
let (result, bindings) = Project.evaluate("1+2")
(result->Reducer_Value.toStringResult, bindings->Reducer_Value.toStringRecord)->expect ==
("Ok(3)", "{}")
},
)
})
})
})

View File

@ -10,9 +10,7 @@ describe("ReducerProject Tutorial", () => {
describe("Multi source", () => {
/*
Case "Running multiple sources" */
test(
"Chaining",
() => {
test("Chaining", () => {
let project = Project.createProject()
/* This time let's add 3 sources and chain them together */
project->Project.setSource("source1", "x=1")
@ -34,12 +32,9 @@ describe("ReducerProject Tutorial", () => {
(result3->Reducer_Value.toStringResult, bindings3->Reducer_Value.toStringRecord)->expect ==
("Ok(())", "{z: 3}")
},
)
})
test(
"Depending",
() => {
test("Depending", () => {
/* Instead of chaining the sources, we could have a dependency tree */
/* The point here is that any source can depend on multiple sources */
let project = Project.createProject()
@ -61,12 +56,9 @@ describe("ReducerProject Tutorial", () => {
(result3->Reducer_Value.toStringResult, bindings3->Reducer_Value.toStringRecord)->expect ==
("Ok(())", "{z: 3}")
},
)
})
test(
"Intro to including",
() => {
test("Intro to including", () => {
/* Though it would not be practical for a storybook,
let's write the same project above with includes.
You will see that parsing includes is setting the dependencies the same way as before. */
@ -107,7 +99,6 @@ describe("ReducerProject Tutorial", () => {
- And the depended source1 and source2 is not already there in the project
- If you knew the includes before hand there would not be point of the include directive.
More on those on the next section. */
},
)
})
})
})

View File

@ -24,20 +24,15 @@ Here we will finally proceed to a real life scenario. */
)
/* We need to parse includes after changing the source */
project->Project.parseIncludes("main")
test(
"getDependencies",
() => {
test("getDependencies", () => {
/* Parse includes has set the dependencies */
project->Project.getDependencies("main")->expect == ["common"]
/* If there were no includes than there would be no dependencies */
/* However if there was a syntax error at includes then would be no dependencies also */
/* Therefore looking at dependencies is not the right way to load includes */
/* getDependencies does not distinguish between setContinues or parseIncludes */
},
)
test(
"getIncludes",
() => {
})
test("getIncludes", () => {
/* Parse includes has set the includes */
switch project->Project.getIncludes("main") {
| Ok(includes) => includes->expect == ["common"]
@ -47,23 +42,17 @@ Here we will finally proceed to a real life scenario. */
Otherwise you get the includes.
If there is no syntax error then you can load that file and use setSource to add it to the project.
And so on recursively... */
},
)
test(
"getDependents",
() => {
})
test("getDependents", () => {
/* For any reason, you are able to query what other sources
include or depend on the current source.
But you don't need to use this to execute the projects.
It is provided for completeness of information. */
project->Project.getDependents("main")->expect == []
/* Nothing is depending on or including main */
},
)
})
describe(
"Real Like",
() => {
describe("Real Like", () => {
/* Now let's look at recursive and possibly cyclic includes */
/* There is no function provided to load the include files.
Because we have no idea if will it be an ordinary function or will it use promises.
@ -99,8 +88,7 @@ Here we will finally proceed to a real life scenario. */
| Error(err) => err->SqError.toString->Js.Exn.raiseError
| Ok(includes) =>
includes->Belt.Array.forEach(
newIncludeName => {
includes->Belt.Array.forEach(newIncludeName => {
/* We have got one of the new includes.
Let's load it and add it to the project */
let newSource = loadSource(newIncludeName)
@ -109,8 +97,7 @@ Here we will finally proceed to a real life scenario. */
/* Of course the new source might have includes too. */
/* Let's recursively load them */
project->loadIncludesRecursively(newIncludeName, newVisited)
},
)
})
}
}
}
@ -156,18 +143,12 @@ Here we will finally proceed to a real life scenario. */
let result = project->Project.getResult("main")
let bindings = project->Project.getBindings("main")
/* And see the result and bindings.. */
test(
"recursive includes",
() => {
(
result->Reducer_Value.toStringResult,
bindings->Reducer_Value.toStringRecord,
)->expect == ("Ok(6)", "{a: 6,b: 2}")
test("recursive includes", () => {
(result->Reducer_Value.toStringResult, bindings->Reducer_Value.toStringRecord)->expect ==
("Ok(6)", "{a: 6,b: 2}")
/* Everything as expected */
},
)
},
)
})
})
})
describe("Includes myFile as myVariable", () => {
@ -182,20 +163,14 @@ Here we will finally proceed to a real life scenario. */
`,
)
Project.parseIncludes(project, "main")
test(
"getDependencies",
() => {
test("getDependencies", () => {
Project.getDependencies(project, "main")->expect == ["common"]
},
)
test(
"getIncludes",
() => {
})
test("getIncludes", () => {
switch Project.getIncludes(project, "main") {
| Ok(includes) => includes->expect == ["common"]
| Error(err) => err->SqError.toString->fail
}
},
)
})
})
})

View File

@ -30,9 +30,8 @@ describe("ReducerProject Tutorial", () => {
})
test("userResults", () => {
let userResultsAsString = Belt.Array.map(
userResults,
aResult => aResult->Reducer_Value.toStringResult,
let userResultsAsString = Belt.Array.map(userResults, aResult =>
aResult->Reducer_Value.toStringResult
)
userResultsAsString->expect == ["Ok(2)", "Ok(4)", "Ok(6)", "Ok(8)", "Ok(10)"]
})

View File

@ -99,19 +99,15 @@ describe("FunctionRegistry Library", () => {
})
describe("Fn auto-testing", () => {
testAll(
"tests of validity",
examples,
r => {
testAll("tests of validity", examples, r => {
expectEvalToBeOk(r)
},
)
})
testAll(
"tests of type",
E.A.to_list(
FunctionRegistry_Core.Registry.allExamplesWithFns(registry)->E.A2.filter(
((fn, _)) => E.O.isSome(fn.output),
FunctionRegistry_Core.Registry.allExamplesWithFns(registry)->E.A2.filter(((fn, _)) =>
E.O.isSome(fn.output)
),
),
((fn, example)) => {

View File

@ -45,12 +45,12 @@ let toExtDist: option<DistributionTypes.genericDist> => DistributionTypes.generi
let unpackFloat = x => x->toFloat->toExtFloat
let unpackDist = y => y->toDist->toExtDist
let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean, stdev}))
let mkBeta = (alpha, beta) => DistributionTypes.Symbolic(#Beta({alpha, beta}))
let mkNormal = (mean, stdev) => DistributionTypes.Symbolic(#Normal({mean: mean, stdev: stdev}))
let mkBeta = (alpha, beta) => DistributionTypes.Symbolic(#Beta({alpha: alpha, beta: beta}))
let mkExponential = rate => DistributionTypes.Symbolic(#Exponential({rate: rate}))
let mkUniform = (low, high) => DistributionTypes.Symbolic(#Uniform({low, high}))
let mkCauchy = (local, scale) => DistributionTypes.Symbolic(#Cauchy({local, scale}))
let mkLognormal = (mu, sigma) => DistributionTypes.Symbolic(#Lognormal({mu, sigma}))
let mkUniform = (low, high) => DistributionTypes.Symbolic(#Uniform({low: low, high: high}))
let mkCauchy = (local, scale) => DistributionTypes.Symbolic(#Cauchy({local: local, scale: scale}))
let mkLognormal = (mu, sigma) => DistributionTypes.Symbolic(#Lognormal({mu: mu, sigma: sigma}))
let mkDelta = x => DistributionTypes.Symbolic(#Float(x))
let normalMake = SymbolicDist.Normal.make

View File

@ -39,7 +39,7 @@
],
"author": "Quantified Uncertainty Research Institute",
"dependencies": {
"@rescript/std": "^10.0.0",
"@rescript/std": "^9.1.4",
"@stdlib/stats": "^0.0.13",
"jstat": "^1.9.5",
"lodash": "^4.17.21",
@ -58,7 +58,7 @@
"peggy": "^2.0.1",
"prettier": "^2.7.1",
"reanalyze": "^2.23.0",
"rescript": "^10.0.0",
"rescript": "^9.1.4",
"rescript-fast-check": "^1.1.1",
"rescript-js-map": "^1.1.0",
"ts-jest": "^29.0.3",

View File

@ -141,7 +141,6 @@ let rec run = (~env: env, functionCallInfo: functionCallInfo): outputType => {
Js.log2("Console log requested: ", dist)
Dist(dist)
}
| #ToDist(Normalize) => dist->GenericDist.normalize->Dist
| #ToScore(LogScore(answer, prior)) =>
GenericDist.Score.logScore(~estimate=dist, ~answer, ~prior, ~env)

View File

@ -99,7 +99,6 @@ let toFloatOperation = (
}
}
}
| (#Stdev | #Variance | #Mode) as op =>
switch t {
| SampleSet(s) =>
@ -130,7 +129,7 @@ let toPointSet = (
SampleSetDist.toPointSetDist(
~samples=r,
~samplingInputs={
sampleCount,
sampleCount: sampleCount,
outputXYPoints: xyPointLength,
pointSetDistLength: xyPointLength,
kernelWidth: None,
@ -428,7 +427,6 @@ module AlgebraicCombination = {
~toSampleSetFn,
)
}
| (None, AsMonteCarlo) =>
StrategyCallOnValidatedInputs.monteCarlo(toSampleSetFn, arithmeticOperation, t1, t2)
| (None, AsSymbolic) =>
@ -445,7 +443,6 @@ module AlgebraicCombination = {
)}`
Error(RequestedStrategyInvalidError(errString))
}
| Some(convOp) => StrategyCallOnValidatedInputs.convolution(toPointSetFn, convOp, t1, t2)
}
}

View File

@ -69,7 +69,7 @@ let toDiscretePointMassesFromTriangulars = (
()
}
{n: n - 2, masses, means, variances}
{n: n - 2, masses: masses, means: means, variances: variances}
} else {
for i in 1 to n - 2 {
// area of triangle = width * height / 2
@ -91,7 +91,7 @@ let toDiscretePointMassesFromTriangulars = (
) |> ignore
()
}
{n: n - 2, masses, means, variances}
{n: n - 2, masses: masses, means: means, variances: variances}
}
}
@ -184,7 +184,7 @@ let toDiscretePointMassesFromDiscrete = (s: PointSetTypes.xyShape): pointMassesW
let means: array<float> = Belt.Array.makeBy(n, i => xs[i])
let variances: array<float> = Belt.Array.makeBy(n, _ => 0.0)
{n, masses, means, variances}
{n: n, masses: masses, means: means, variances: variances}
}
type argumentPosition = First | Second

View File

@ -45,16 +45,16 @@ module Analysis = {
let getShape = (t: t) => t.xyShape
let interpolation = (t: t) => t.interpolation
let make = (~interpolation=#Linear, ~integralSumCache=None, ~integralCache=None, xyShape): t => {
xyShape,
interpolation,
integralSumCache,
integralCache,
xyShape: xyShape,
interpolation: interpolation,
integralSumCache: integralSumCache,
integralCache: integralCache,
}
let shapeMap = (fn, {xyShape, interpolation, integralSumCache, integralCache}: t): t => {
xyShape: fn(xyShape),
interpolation,
integralSumCache,
integralCache,
interpolation: interpolation,
integralSumCache: integralSumCache,
integralCache: integralCache,
}
let lastY = (t: t) => t |> getShape |> XYShape.T.lastY
let oShapeMap = (fn, {xyShape, interpolation, integralSumCache, integralCache}: t): option<
@ -135,10 +135,10 @@ let shapeFn = (fn, t: t) => t |> getShape |> fn
let updateIntegralSumCache = (integralSumCache, t: t): t => {
...t,
integralSumCache,
integralSumCache: integralSumCache,
}
let updateIntegralCache = (integralCache, t: t): t => {...t, integralCache}
let updateIntegralCache = (integralCache, t: t): t => {...t, integralCache: integralCache}
let sum = (
~integralSumCachesFn: (float, float) => option<float>=(_, _) => None,

View File

@ -4,14 +4,14 @@ open Distributions
type t = PointSetTypes.discreteShape
let make = (~integralSumCache=None, ~integralCache=None, xyShape): t => {
xyShape,
integralSumCache,
integralCache,
xyShape: xyShape,
integralSumCache: integralSumCache,
integralCache: integralCache,
}
let shapeMap = (fn, {xyShape, integralSumCache, integralCache}: t): t => {
xyShape: fn(xyShape),
integralSumCache,
integralCache,
integralSumCache: integralSumCache,
integralCache: integralCache,
}
let getShape = (t: t) => t.xyShape
let oShapeMap = (fn, {xyShape, integralSumCache, integralCache}: t): option<t> =>
@ -63,12 +63,12 @@ let reduce = (
let updateIntegralSumCache = (integralSumCache, t: t): t => {
...t,
integralSumCache,
integralSumCache: integralSumCache,
}
let updateIntegralCache = (integralCache, t: t): t => {
...t,
integralCache,
integralCache: integralCache,
}
/* This multiples all of the data points together and creates a new discrete distribution from the results.

View File

@ -4,10 +4,10 @@ open Distributions
type t = PointSetTypes.mixedShape
let make = (~integralSumCache=None, ~integralCache=None, ~continuous, ~discrete): t => {
continuous,
discrete,
integralSumCache,
integralCache,
continuous: continuous,
discrete: discrete,
integralSumCache: integralSumCache,
integralCache: integralCache,
}
let totalLength = (t: t): int => {
@ -35,7 +35,7 @@ let toDiscrete = ({discrete}: t) => Some(discrete)
let updateIntegralCache = (integralCache, t: t): t => {
...t,
integralCache,
integralCache: integralCache,
}
let combinePointwise = (

View File

@ -79,8 +79,8 @@ module MixedPoint = {
type t = mixedPoint
let toContinuousValue = (t: t) => t.continuous
let toDiscreteValue = (t: t) => t.discrete
let makeContinuous = (continuous: float): t => {continuous, discrete: 0.0}
let makeDiscrete = (discrete: float): t => {continuous: 0.0, discrete}
let makeContinuous = (continuous: float): t => {continuous: continuous, discrete: 0.0}
let makeDiscrete = (discrete: float): t => {continuous: 0.0, discrete: discrete}
let fmap = (fn: float => float, t: t) => {
continuous: fn(t.continuous),

View File

@ -7,7 +7,7 @@ module Normal = {
type t = normal
let make = (mean: float, stdev: float): result<symbolicDist, string> =>
stdev > 0.0
? Ok(#Normal({mean, stdev}))
? Ok(#Normal({mean: mean, stdev: stdev}))
: Error("Standard deviation of normal distribution must be larger than 0")
let pdf = (x, t: t) => Jstat.Normal.pdf(x, t.mean, t.stdev)
let cdf = (x, t: t) => Jstat.Normal.cdf(x, t.mean, t.stdev)
@ -15,7 +15,7 @@ module Normal = {
let from90PercentCI = (low, high) => {
let mean = E.A.Floats.mean([low, high])
let stdev = (high -. low) /. (2. *. normal95confidencePoint)
#Normal({mean, stdev})
#Normal({mean: mean, stdev: stdev})
}
let inv = (p, t: t) => Jstat.Normal.inv(p, t.mean, t.stdev)
let sample = (t: t) => Jstat.Normal.sample(t.mean, t.stdev)
@ -25,12 +25,12 @@ module Normal = {
let add = (n1: t, n2: t) => {
let mean = n1.mean +. n2.mean
let stdev = Js.Math.sqrt(n1.stdev ** 2. +. n2.stdev ** 2.)
#Normal({mean, stdev})
#Normal({mean: mean, stdev: stdev})
}
let subtract = (n1: t, n2: t) => {
let mean = n1.mean -. n2.mean
let stdev = Js.Math.sqrt(n1.stdev ** 2. +. n2.stdev ** 2.)
#Normal({mean, stdev})
#Normal({mean: mean, stdev: stdev})
}
// TODO: is this useful here at all? would need the integral as well ...
@ -38,7 +38,7 @@ module Normal = {
let mean =
(n1.mean *. n2.stdev ** 2. +. n2.mean *. n1.stdev ** 2.) /. (n1.stdev ** 2. +. n2.stdev ** 2.)
let stdev = 1. /. (1. /. n1.stdev ** 2. +. 1. /. n2.stdev ** 2.)
#Normal({mean, stdev})
#Normal({mean: mean, stdev: stdev})
}
let operate = (operation: Operation.Algebraic.t, n1: t, n2: t) =>
@ -88,7 +88,7 @@ module Cauchy = {
type t = cauchy
let make = (local, scale): result<symbolicDist, string> =>
scale > 0.0
? Ok(#Cauchy({local, scale}))
? Ok(#Cauchy({local: local, scale: scale}))
: Error("Cauchy distribution scale parameter must larger than 0.")
let pdf = (x, t: t) => Jstat.Cauchy.pdf(x, t.local, t.scale)
let cdf = (x, t: t) => Jstat.Cauchy.cdf(x, t.local, t.scale)
@ -102,7 +102,7 @@ module Triangular = {
type t = triangular
let make = (low, medium, high): result<symbolicDist, string> =>
low < medium && medium < high
? Ok(#Triangular({low, medium, high}))
? Ok(#Triangular({low: low, medium: medium, high: high}))
: Error("Triangular values must be increasing order.")
let pdf = (x, t: t) => Jstat.Triangular.pdf(x, t.low, t.high, t.medium) // not obvious in jstat docs that high comes before medium?
let cdf = (x, t: t) => Jstat.Triangular.cdf(x, t.low, t.high, t.medium)
@ -116,7 +116,7 @@ module Beta = {
type t = beta
let make = (alpha, beta) =>
alpha > 0.0 && beta > 0.0
? Ok(#Beta({alpha, beta}))
? Ok(#Beta({alpha: alpha, beta: beta}))
: Error("Beta distribution parameters must be positive")
let pdf = (x, t: t) => Jstat.Beta.pdf(x, t.alpha, t.beta)
let cdf = (x, t: t) => Jstat.Beta.cdf(x, t.alpha, t.beta)
@ -150,7 +150,7 @@ module Lognormal = {
type t = lognormal
let make = (mu, sigma) =>
sigma > 0.0
? Ok(#Lognormal({mu, sigma}))
? Ok(#Lognormal({mu: mu, sigma: sigma}))
: Error("Lognormal standard deviation must be larger than 0")
let pdf = (x, t: t) => Jstat.Lognormal.pdf(x, t.mu, t.sigma)
let cdf = (x, t: t) => Jstat.Lognormal.cdf(x, t.mu, t.sigma)
@ -164,7 +164,7 @@ module Lognormal = {
let logHigh = Js.Math.log(high)
let mu = E.A.Floats.mean([logLow, logHigh])
let sigma = (logHigh -. logLow) /. (2.0 *. normal95confidencePoint)
#Lognormal({mu, sigma})
#Lognormal({mu: mu, sigma: sigma})
}
let fromMeanAndStdev = (mean, stdev) => {
// https://math.stackexchange.com/questions/2501783/parameters-of-a-lognormal-distribution
@ -174,7 +174,7 @@ module Lognormal = {
let meanSquared = mean ** 2.
let mu = 2. *. Js.Math.log(mean) -. 0.5 *. Js.Math.log(variance +. meanSquared)
let sigma = Js.Math.sqrt(Js.Math.log(variance /. meanSquared +. 1.))
Ok(#Lognormal({mu, sigma}))
Ok(#Lognormal({mu: mu, sigma: sigma}))
} else {
Error("Lognormal standard deviation must be larger than 0")
}
@ -184,14 +184,14 @@ module Lognormal = {
// https://wikiless.org/wiki/Log-normal_distribution?lang=en#Multiplication_and_division_of_independent,_log-normal_random_variables
let mu = l1.mu +. l2.mu
let sigma = Js.Math.sqrt(l1.sigma ** 2. +. l2.sigma ** 2.)
#Lognormal({mu, sigma})
#Lognormal({mu: mu, sigma: sigma})
}
let divide = (l1, l2) => {
let mu = l1.mu -. l2.mu
// We believe the ratiands will have covariance zero.
// See here https://stats.stackexchange.com/questions/21735/what-are-the-mean-and-variance-of-the-ratio-of-two-lognormal-variables for details
let sigma = Js.Math.sqrt(l1.sigma ** 2. +. l2.sigma ** 2.)
#Lognormal({mu, sigma})
#Lognormal({mu: mu, sigma: sigma})
}
let operate = (operation: Operation.Algebraic.t, n1: t, n2: t) =>
switch operation {
@ -220,7 +220,7 @@ module Lognormal = {
module Uniform = {
type t = uniform
let make = (low, high) =>
high > low ? Ok(#Uniform({low, high})) : Error("High must be larger than low")
high > low ? Ok(#Uniform({low: low, high: high})) : Error("High must be larger than low")
let pdf = (x, t: t) => Jstat.Uniform.pdf(x, t.low, t.high)
let cdf = (x, t: t) => Jstat.Uniform.cdf(x, t.low, t.high)
@ -239,7 +239,9 @@ module Uniform = {
module Logistic = {
type t = logistic
let make = (location, scale) =>
scale > 0.0 ? Ok(#Logistic({location, scale})) : Error("Scale must be positive")
scale > 0.0
? Ok(#Logistic({location: location, scale: scale}))
: Error("Scale must be positive")
let pdf = (x, t: t) => Stdlib.Logistic.pdf(x, t.location, t.scale)
let cdf = (x, t: t) => Stdlib.Logistic.cdf(x, t.location, t.scale)
@ -283,7 +285,7 @@ module Gamma = {
let make = (shape: float, scale: float) => {
if shape > 0. {
if scale > 0. {
Ok(#Gamma({shape, scale}))
Ok(#Gamma({shape: shape, scale: scale}))
} else {
Error("scale must be larger than 0")
}
@ -541,6 +543,6 @@ module T = {
| _ =>
let xs = interpolateXs(~xSelection, d, sampleCount)
let ys = xs |> E.A.fmap(x => pdf(x, d))
Continuous(Continuous.make(~integralSumCache=Some(1.0), {xs, ys}))
Continuous(Continuous.make(~integralSumCache=Some(1.0), {xs: xs, ys: ys}))
}
}

View File

@ -23,7 +23,7 @@ let makeFn = (
name: string,
inputs: array<frType>,
fn: array<Reducer_T.value> => result<Reducer_T.value, errorMessage>,
) => makeFnMany(name, [{inputs, fn}])
) => makeFnMany(name, [{inputs: inputs, fn: fn}])
let library = [
Make.ff2f(~name="add", ~fn=(x, y) => x +. y, ()), // infix + (see Reducer/Reducer_Peggy/helpers.ts)
@ -62,7 +62,6 @@ let library = [
let answer = Js.String2.concat(a, b)
answer->Reducer_T.IEvString->Ok
}
| _ => Error(impossibleError)
}
}),
@ -73,7 +72,6 @@ let library = [
let _ = Js.Array2.pushMany(a, b)
a->Reducer_T.IEvArray->Ok
}
| _ => Error(impossibleError)
}
}),
@ -83,7 +81,6 @@ let library = [
Js.log(value->Reducer_Value.toString)
value->Ok
}
| _ => Error(impossibleError)
}
}),
@ -93,7 +90,6 @@ let library = [
Js.log(`${label}: ${value->Reducer_Value.toString}`)
value->Ok
}
| _ => Error(impossibleError)
}
}),

View File

@ -135,13 +135,11 @@ module Integration = {
let wrappedResult = result->Reducer_T.IEvNumber->Ok
wrappedResult
}
| (Error(b), _) => Error(b)
| (_, Error(b)) => Error(b)
}
resultWithOuterPoints
}
| Error(b) =>
("Integration error 2 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." ++
"Original error: " ++
@ -364,7 +362,6 @@ module DiminishingReturns = {
result[indexOfBiggestDMR] = value
Ok(result)
}
| Error(b) => Error(b)
}
@ -374,12 +371,10 @@ module DiminishingReturns = {
}
Ok(newAcc)
}
| Error(b) => Error(b)
}
newAccWrapped
}
| Error(b) => Error(b)
}
})
@ -432,12 +427,10 @@ module DiminishingReturns = {
)
result
}
| Error(b) => Error(b)
}
result
}
| _ =>
"Error in Danger.diminishingMarginalReturnsForTwoFunctions"
->SqError.Message.REOther

View File

@ -20,7 +20,6 @@ module Declaration = {
->E.A.R.firstErrorOrOpen
->E.R2.fmap(args => Reducer_T.IEvDeclaration(Declaration.make(lambda, args)))
}
| Error(r) => Error(r)
| Ok(_) => Error(impossibleErrorString)
}

View File

@ -140,7 +140,6 @@ module Old = {
| Error(err) => error(err)
}
}
| Some(IEvNumber(_))
| Some(IEvDistribution(_)) =>
switch parseDistributionArray(args) {
@ -193,7 +192,6 @@ module Old = {
}
Helpers.toFloatFn(fn, dist, ~env)
}
| ("integralSum", [IEvDistribution(dist)]) => Helpers.toFloatFn(#IntegralSum, dist, ~env)
| ("toString", [IEvDistribution(dist)]) => Helpers.toStringFn(ToString, dist, ~env)
| ("sparkline", [IEvDistribution(dist)]) =>

View File

@ -19,7 +19,6 @@ let inputsToDist = (inputs: array<Reducer_T.value>, xyShapeToPointSetDist) => {
| _ => impossibleError->SqError.Message.throw
}
}
| _ => impossibleError->SqError.Message.throw
}
)

View File

@ -61,7 +61,6 @@ module FRType = {
let input = ((name, frType): frTypeRecordParam) => `${name}: ${toString(frType)}`
`{${r->E.A2.fmap(input)->E.A2.joinWith(", ")}}`
}
| FRTypeArray(r) => `list(${toString(r)})`
| FRTypeLambda => `lambda`
| FRTypeString => `string`
@ -133,9 +132,9 @@ module FnDefinition = {
}
let make = (~name, ~inputs, ~run, ()): t => {
name,
inputs,
run,
name: name,
inputs: inputs,
run: run,
}
}
@ -161,14 +160,14 @@ module Function = {
~isExperimental=false,
(),
): t => {
name,
nameSpace,
definitions,
output,
name: name,
nameSpace: nameSpace,
definitions: definitions,
output: output,
examples: examples->E.O2.default([]),
isExperimental,
requiresNamespace,
description,
isExperimental: isExperimental,
requiresNamespace: requiresNamespace,
description: description,
}
let toJson = (t: t): functionJson => {
@ -204,19 +203,15 @@ module Registry = {
fn.requiresNamespace ? [] : [def.name],
]->E.A.concatMany
names->Belt.Array.reduce(
acc,
(acc, name) => {
names->Belt.Array.reduce(acc, (acc, name) => {
switch acc->Belt.Map.String.get(name) {
| Some(fns) => {
let _ = fns->Js.Array2.push(def) // mutates the array, no need to update acc
acc
}
| None => acc->Belt.Map.String.set(name, [def])
}
},
)
})
})
)
}
@ -250,7 +245,6 @@ module Registry = {
| None => REOther(showNameMatchDefinitions())->Error
}
}
| None => RESymbolNotFound(fnName)->Error
}
}

View File

@ -34,7 +34,6 @@ module Prepare = {
let n2 = map->Belt.Map.String.getExn(arg2)
Ok([n1, n2])
}
| _ => Error(impossibleErrorString)
}
@ -46,7 +45,6 @@ module Prepare = {
let n3 = map->Belt.Map.String.getExn(arg3)
Ok([n1, n2, n3])
}
| _ => Error(impossibleErrorString)
}
}

View File

@ -44,4 +44,4 @@ let removeResult = ({namespace} as bindings: t): t => {
let locals = ({namespace}: t): Reducer_T.namespace => namespace
let fromNamespace = (namespace: Reducer_Namespace.t): t => {namespace, parent: None}
let fromNamespace = (namespace: Reducer_Namespace.t): t => {namespace: namespace, parent: None}

View File

@ -6,7 +6,7 @@ let createContext = (stdLib: Reducer_Namespace.t, environment: Reducer_T.environ
{
frameStack: list{},
bindings: stdLib->Reducer_Bindings.fromNamespace->Reducer_Bindings.extend,
environment,
environment: environment,
inFunction: None,
}
}

View File

@ -123,7 +123,6 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
)
(result, context)
}
| _ => RENotAFunction(lambda->Reducer_Value.toString)->throwFrom(expression, context)
}
}

View File

@ -23,8 +23,8 @@ let make = (): t => list{}
let extend = (t: t, name: string, location: option<Reducer_Peggy_Parse.location>) =>
t->Belt.List.add({
name,
location,
name: name,
location: location,
})
// this is useful for SyntaxErrors

View File

@ -43,10 +43,10 @@ let makeLambda = (
FnLambda({
// context: bindings,
name,
name: name,
body: lambda,
parameters,
location,
parameters: parameters,
location: location,
})
}
@ -54,8 +54,8 @@ let makeLambda = (
let makeFFILambda = (name: string, body: Reducer_T.lambdaBody): t => FnBuiltin({
// Note: current bindings could be accidentally exposed here through context (compare with native lambda implementation above, where we override them with local bindings).
// But FunctionRegistry API is too limited for that to matter. Please take care not to violate that in the future by accident.
body,
name,
body: body,
name: name,
})
// this function doesn't scale to FunctionRegistry's polymorphic functions

View File

@ -113,7 +113,7 @@ let nodeToAST = (node: node) => {
| _ => raise(UnsupportedPeggyNodeType(node["type"]))
}
{location: node["location"], content}
{location: node["location"], content: content}
}
let nodeIdentifierToAST = (node: nodeIdentifier) => {

View File

@ -68,7 +68,7 @@ let rec fromNode = (node: Parse.node): expression => {
}
{
ast,
content,
ast: ast,
content: content,
}
}

View File

@ -216,7 +216,6 @@ let tryRunWithResult = (
project->setResult(sourceId, Error(error))
Error(error)
}
| Ok(_prevResult) => {
project->doLinkAndRun(sourceId)
project->getResultOption(sourceId)->Belt.Option.getWithDefault(rPrevResult)

View File

@ -6,7 +6,7 @@ type t = T.t
let emptyItem = (sourceId: string): projectItem => {
source: "",
sourceId,
sourceId: sourceId,
rawParse: None,
expression: None,
continuation: Reducer_Namespace.make(),
@ -76,7 +76,7 @@ let resetIncludes = (r: t): t => {
}
let setSource = (r: t, source: T.sourceArgumentType): t =>
{...r, source}->resetIncludes->touchSource
{...r, source: source}->resetIncludes->touchSource
let setRawParse = (r: t, rawParse: T.rawParseArgumentType): t =>
{...r, rawParse: Some(rawParse)}->touchRawParse
@ -86,7 +86,7 @@ let setExpression = (r: t, expression: T.expressionArgumentType): t =>
let setContinuation = (r: t, continuation: T.continuationArgumentType): t => {
...r,
continuation,
continuation: continuation,
}
let setResult = (r: t, result: T.resultArgumentType): t => {
@ -110,23 +110,24 @@ let getPastChain = (this: t): array<string> => {
Js.Array2.concat(getDirectIncludes(this), getContinues(this))
}
let setContinues = (this: t, continues: array<string>): t => {...this, continues}->touchSource
let setContinues = (this: t, continues: array<string>): t =>
{...this, continues: continues}->touchSource
let removeContinues = (this: t): t => {...this, continues: []}->touchSource
let setIncludes = (this: t, includes: T.includesType): t => {
...this,
includes,
includes: includes,
}
let setImportAsVariables = (this: t, includeAsVariables: T.importAsVariablesType): t => {
...this,
includeAsVariables,
includeAsVariables: includeAsVariables,
}
let setDirectImports = (this: t, directIncludes: array<string>): t => {
...this,
directIncludes,
directIncludes: directIncludes,
}
let parseIncludes = (this: t): t => {
@ -143,9 +144,9 @@ let parseIncludes = (this: t): t => {
->Belt.Array.map(((_variable, file)) => file)
{
...this,
includes,
includeAsVariables,
directIncludes,
includes: includes,
includeAsVariables: includeAsVariables,
directIncludes: directIncludes,
}
}
}

View File

@ -54,7 +54,6 @@ module Message = {
}
answer
}
| REMacroNotFound(macro) => `Macro not found: ${macro}`
| RENotAFunction(valueString) => `${valueString} is not a function`
| RERecordPropertyNotFound(msg, index) => `${msg}: ${index}`
@ -94,8 +93,8 @@ type t = {
exception SqException(t)
let fromMessageWithFrameStack = (message: Message.t, frameStack: Reducer_FrameStack.t): t => {
message,
frameStack,
message: message,
frameStack: frameStack,
}
// this shouldn't be used much, since frame stack will be empty

View File

@ -18,7 +18,6 @@ let stdLib: Reducer_T.namespace = {
| None => REArrayIndexNotFound("Array index not found", index)->SqError.Message.throw
}
}
| [IEvRecord(dict), IEvString(sIndex)] =>
switch Belt.Map.String.get(dict, sIndex) {
| Some(value) => value

View File

@ -9,13 +9,13 @@ type declaration<'a> = {
module ContinuousFloatArg = {
let make = (min: float, max: float): arg => {
Float({min, max})
Float({min: min, max: max})
}
}
module ContinuousTimeArg = {
let make = (min: Js.Date.t, max: Js.Date.t): arg => {
Date({min, max})
Date({min: min, max: max})
}
}
@ -33,7 +33,7 @@ module Arg = {
}
let make = (fn: 'a, args: array<arg>): declaration<'a> => {
{fn, args}
{fn: fn, args: args}
}
let toString = (r: declaration<'a>, fnToString): string => {

View File

@ -85,8 +85,8 @@ module T = {
}
let square = mapX(x => x ** 2.0)
let zip = ({xs, ys}: t) => Belt.Array.zip(xs, ys)
let fromArray = ((xs, ys)): t => {xs, ys}
let fromArrays = (xs, ys): t => {xs, ys}
let fromArray = ((xs, ys)): t => {xs: xs, ys: ys}
let fromArrays = (xs, ys): t => {xs: xs, ys: ys}
let accumulateYs = (fn, p: t) => fromArray((p.xs, E.A.accumulate(fn, p.ys)))
let concat = (t1: t, t2: t) => {
let cxs = Array.concat(list{t1.xs, t2.xs})
@ -142,7 +142,7 @@ module T = {
}
let make = (~xs: array<float>, ~ys: array<float>) => {
let attempt: t = {xs, ys}
let attempt: t = {xs: xs, ys: ys}
switch Validator.validate(attempt) {
| Some(error) => Error(error)
| None => Ok(attempt)
@ -452,7 +452,6 @@ module PointwiseCombination = {
let _ = Js.Array.push(fn(y1, y2), newYs)
let _ = Js.Array.push(x, newXs)
}
| None => ()
}
}
@ -559,7 +558,7 @@ module Range = {
(xs[x + 1] -. xs[x]) *. ((ys[x] +. ys[x + 1]) /. 2.) +. cumulativeY[x], // dx // (1/2) * (avgY)
)
}
Some({xs, ys: cumulativeY})
Some({xs: xs, ys: cumulativeY})
}
let derivative = mapYsBasedOnRanges(delta_y_over_delta_x)

View File

@ -3037,11 +3037,6 @@
"@react-hook/passive-layout-effect" "^1.2.0"
"@react-hook/resize-observer" "^1.2.1"
"@rescript/std@^10.0.0":
version "10.0.0"
resolved "https://registry.yarnpkg.com/@rescript/std/-/std-10.0.0.tgz#11996296739d7f0d2949283c93b4d14e9ed4589d"
integrity sha512-DFwX5vWASZtvjFdqar2VIadvmy2ZBPTnPI2A9EKEkvNR93OUoZygOfvhRaueIQtlS4f9X50E3v2awI9JJG+JsQ==
"@rescript/std@^9.1.4":
version "9.1.4"
resolved "https://registry.yarnpkg.com/@rescript/std/-/std-9.1.4.tgz#94971cb504b10d36d470618fa1c6f0a2d03a6b9b"
@ -16345,10 +16340,10 @@ rescript-js-map@^1.1.0:
dependencies:
rescript-js-iterator "^1.1.0"
rescript@^10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/rescript/-/rescript-10.0.0.tgz#8460bc6f7d94bc580eac02d7c7efdf0a470916b8"
integrity sha512-LhNg/4+0j8NvoFeslgAeYLlzUwkq6kR6l6v8BnZ61VDTxopK2l96uT1lq5lv1aMxzMDynvE2qnX0zalre+6XxA==
rescript@^9.1.4:
version "9.1.4"
resolved "https://registry.yarnpkg.com/rescript/-/rescript-9.1.4.tgz#1eb126f98d6c16942c0bf0df67c050198e580515"
integrity sha512-aXANK4IqecJzdnDpJUsU6pxMViCR5ogAxzuqS0mOr8TloMnzAjJFu63fjD6LCkWrKAhlMkFFzQvVQYaAaVkFXw==
resize-observer-polyfill@^1.5.1:
version "1.5.1"