TS & components (WIP)

This commit is contained in:
Vyacheslav Matyukhin 2022-08-27 21:46:43 +04:00
parent 68ddf35387
commit 32cefb40da
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
33 changed files with 1348 additions and 678 deletions

View File

@ -2,10 +2,10 @@ import * as React from "react";
import {
Distribution,
result,
distributionError,
distributionErrorToString,
squiggleExpression,
DistributionError,
SquiggleValue,
resultMap,
SquiggleRecord,
} from "@quri/squiggle-lang";
import { Vega } from "react-vega";
import { ErrorAlert } from "./Alert";
@ -36,9 +36,7 @@ export function defaultPlot(distribution: Distribution): Plot {
return { distributions: [{ name: "default", distribution }] };
}
export function makePlot(record: {
[key: string]: squiggleExpression;
}): Plot | void {
export function makePlot(record: SquiggleRecord): Plot | void {
const plotResult = parsePlot(record);
if (plotResult.tag === "Ok") {
return plotResult.value;
@ -50,18 +48,17 @@ export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
const [sized] = useSize((size) => {
let shapes = flattenResult(
plot.distributions.map((x) =>
resultMap(x.distribution.pointSet(), (shape) => ({
resultMap(x.distribution.pointSet(), (pointSet) => ({
...pointSet.asShape(),
name: x.name,
// color: x.color, // not supported yet
continuous: shape.continuous,
discrete: shape.discrete,
}))
)
);
if (shapes.tag === "Error") {
return (
<ErrorAlert heading="Distribution Error">
{distributionErrorToString(shapes.value)}
{shapes.value.toString()}
</ErrorAlert>
);
}
@ -134,18 +131,18 @@ const SummaryTable: React.FC<SummaryTableProps> = ({ distribution }) => {
const p90 = distribution.inv(0.9);
const p95 = distribution.inv(0.95);
const hasResult = (x: result<number, distributionError>): boolean =>
const hasResult = (x: result<number, DistributionError>): boolean =>
x.tag === "Ok";
const unwrapResult = (
x: result<number, distributionError>
x: result<number, DistributionError>
): React.ReactNode => {
if (x.tag === "Ok") {
return <NumberShower number={x.value} />;
} else {
return (
<ErrorAlert heading="Distribution Error">
{distributionErrorToString(x.value)}
{x.value.toString()}
</ErrorAlert>
);
}

View File

@ -1,10 +1,5 @@
import * as React from "react";
import {
lambdaValue,
environment,
runForeign,
errorValueToString,
} from "@quri/squiggle-lang";
import { LambdaValue, environment, runForeign } from "@quri/squiggle-lang";
import { FunctionChart1Dist } from "./FunctionChart1Dist";
import { FunctionChart1Number } from "./FunctionChart1Number";
import { DistributionPlottingSettings } from "./DistributionChart";
@ -17,7 +12,7 @@ export type FunctionChartSettings = {
};
interface FunctionChartProps {
fn: lambdaValue;
fn: LambdaValue;
chartSettings: FunctionChartSettings;
distributionPlotSettings: DistributionPlottingSettings;
environment: environment;

View File

@ -1,11 +1,7 @@
import * as React from "react";
import {
squiggleExpression,
bindings,
SquiggleValue,
environment,
jsImports,
defaultImports,
defaultBindings,
defaultEnvironment,
} from "@quri/squiggle-lang";
import { useSquiggle } from "../lib/hooks";
@ -27,14 +23,12 @@ export interface SquiggleChartProps {
/** If the result is a function, the amount of stops sampled */
diagramCount?: number;
/** When the squiggle code gets reevaluated */
onChange?(expr: squiggleExpression | undefined): void;
onChange?(expr: SquiggleValue | undefined): void;
/** CSS width of the element */
width?: number;
height?: number;
/** Bindings of previous variables declared */
bindings?: bindings;
/** JS imported parameters */
jsImports?: jsImports;
// jsImports?: jsImports;
/** Whether to show a summary of the distribution */
showSummary?: boolean;
/** Set the x scale to be logarithmic by deault */
@ -65,8 +59,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
environment,
onChange = defaultOnChange, // defaultOnChange must be constant, don't move its definition here
height = 200,
bindings = defaultBindings,
jsImports = defaultImports,
// jsImports = defaultImports,
showSummary = false,
width,
logX = false,
@ -84,9 +77,8 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
}) => {
const result = useSquiggle({
code,
bindings,
environment,
jsImports,
// jsImports,
onChange,
executionId,
});

View File

@ -1,11 +1,8 @@
import React from "react";
import { CodeEditor } from "./CodeEditor";
import { environment, bindings, jsImports } from "@quri/squiggle-lang";
import { defaultImports, defaultBindings } from "@quri/squiggle-lang";
import { SquiggleContainer } from "./SquiggleContainer";
import { SquiggleChart, SquiggleChartProps } from "./SquiggleChart";
import { useSquigglePartial, useMaybeControlledValue } from "../lib/hooks";
import { SquiggleErrorAlert } from "./SquiggleErrorAlert";
import { useMaybeControlledValue } from "../lib/hooks";
const WrappedCodeEditor: React.FC<{
code: string;
@ -42,51 +39,3 @@ export const SquiggleEditor: React.FC<SquiggleEditorProps> = (props) => {
</SquiggleContainer>
);
};
export interface SquigglePartialProps {
/** The text inside the input (controlled) */
code?: string;
/** The default text inside the input (unControlled) */
defaultCode?: string;
/** when the environment changes. Used again for notebook magic*/
onChange?(expr: bindings | undefined): void;
/** When the code changes */
onCodeChange?(code: string): void;
/** Previously declared variables */
bindings?: bindings;
/** If the output requires monte carlo sampling, the amount of samples */
environment?: environment;
/** Variables imported from js */
jsImports?: jsImports;
}
export const SquigglePartial: React.FC<SquigglePartialProps> = ({
code: controlledCode,
defaultCode = "",
onChange,
onCodeChange,
bindings = defaultBindings,
environment,
jsImports = defaultImports,
}: SquigglePartialProps) => {
const [code, setCode] = useMaybeControlledValue<string>({
value: controlledCode,
defaultValue: defaultCode,
onChange: onCodeChange,
});
const result = useSquigglePartial({
code,
bindings,
environment,
jsImports,
onChange,
});
return (
<SquiggleContainer>
<WrappedCodeEditor code={code} setCode={setCode} />
{result.tag !== "Ok" ? <SquiggleErrorAlert error={result.value} /> : null}
</SquiggleContainer>
);
};

View File

@ -1,11 +1,11 @@
import { errorValue, errorValueToString } from "@quri/squiggle-lang";
import { ErrorValue } from "@quri/squiggle-lang";
import React from "react";
import { ErrorAlert } from "./Alert";
type Props = {
error: errorValue;
error: ErrorValue;
};
export const SquiggleErrorAlert: React.FC<Props> = ({ error }) => {
return <ErrorAlert heading="Error">{errorValueToString(error)}</ErrorAlert>;
return <ErrorAlert heading="Error">{error.toString()}</ErrorAlert>;
};

View File

@ -24,7 +24,7 @@ import {
} from "@heroicons/react/solid";
import clsx from "clsx";
import { defaultBindings, environment } from "@quri/squiggle-lang";
import { environment } from "@quri/squiggle-lang";
import { SquiggleChart, SquiggleChartProps } from "./SquiggleChart";
import { CodeEditor } from "./CodeEditor";
@ -309,8 +309,7 @@ export const SquigglePlayground: FC<PlaygroundProps> = ({
executionId={executionId}
environment={env}
{...vars}
bindings={defaultBindings}
jsImports={imports}
// jsImports={imports}
enableLocalSettings={true}
/>
</div>

View File

@ -1,5 +1,9 @@
import React from "react";
import { squiggleExpression, declaration } from "@quri/squiggle-lang";
import {
DistributionTag,
SquiggleValue,
SquiggleValueTag,
} from "@quri/squiggle-lang";
import { NumberShower } from "../NumberShower";
import { DistributionChart, defaultPlot, makePlot } from "../DistributionChart";
import { FunctionChart, FunctionChartSettings } from "../FunctionChart";
@ -9,6 +13,8 @@ import { ItemSettingsMenu } from "./ItemSettingsMenu";
import { hasMassBelowZero } from "../../lib/distributionUtils";
import { MergedItemSettings } from "./utils";
/*
// DISABLED FOR 0.4 branch, for now
function getRange<a>(x: declaration<a>) {
const first = x.args[0];
switch (first.tag) {
@ -31,6 +37,7 @@ function getChartSettings<a>(x: declaration<a>): FunctionChartSettings {
count: 20,
};
}
*/
const VariableList: React.FC<{
path: string[];
@ -48,7 +55,7 @@ const VariableList: React.FC<{
export interface Props {
/** The output of squiggle's run */
expression: squiggleExpression;
expression: SquiggleValue;
/** Path to the current item, e.g. `['foo', 'bar', '3']` for `foo.bar[3]`; can be empty on the top-level item. */
path: string[];
width?: number;
@ -67,7 +74,7 @@ export const ExpressionViewer: React.FC<Props> = ({
);
}
switch (expression.tag) {
case "number":
case SquiggleValueTag.SvtNumber:
return (
<VariableBox path={path} heading="Number">
{() => (
@ -77,13 +84,15 @@ export const ExpressionViewer: React.FC<Props> = ({
)}
</VariableBox>
);
case "distribution": {
const distType = expression.value.type();
case SquiggleValueTag.SvtDistribution: {
const distType = expression.value.tag;
return (
<VariableBox
path={path}
heading={`Distribution (${distType})\n${
distType === "Symbolic" ? expression.value.toString() : ""
distType === DistributionTag.DtSymbolic
? expression.value.toString()
: ""
}`}
renderSettingsMenu={({ onChange }) => {
const shape = expression.value.pointSet();
@ -112,7 +121,7 @@ export const ExpressionViewer: React.FC<Props> = ({
</VariableBox>
);
}
case "string":
case SquiggleValueTag.SvtString:
return (
<VariableBox path={path} heading="String">
{() => (
@ -126,13 +135,13 @@ export const ExpressionViewer: React.FC<Props> = ({
)}
</VariableBox>
);
case "boolean":
case SquiggleValueTag.SvtBool:
return (
<VariableBox path={path} heading="Boolean">
{() => expression.value.toString()}
</VariableBox>
);
case "symbol":
case SquiggleValueTag.SvtSymbol:
return (
<VariableBox path={path} heading="Symbol">
{() => (
@ -143,38 +152,38 @@ export const ExpressionViewer: React.FC<Props> = ({
)}
</VariableBox>
);
case "call":
case SquiggleValueTag.SvtCall:
return (
<VariableBox path={path} heading="Call">
{() => expression.value}
</VariableBox>
);
case "arraystring":
case SquiggleValueTag.SvtArrayString:
return (
<VariableBox path={path} heading="Array String">
{() => expression.value.map((r) => `"${r}"`).join(", ")}
</VariableBox>
);
case "date":
case SquiggleValueTag.SvtDate:
return (
<VariableBox path={path} heading="Date">
{() => expression.value.toDateString()}
</VariableBox>
);
case "void":
case SquiggleValueTag.SvtVoid:
return (
<VariableBox path={path} heading="Void">
{() => "Void"}
</VariableBox>
);
case "timeDuration": {
case SquiggleValueTag.SvtTimeDuration: {
return (
<VariableBox path={path} heading="Time Duration">
{() => <NumberShower precision={3} number={expression.value} />}
</VariableBox>
);
}
case "lambda":
case SquiggleValueTag.SvtLambda:
return (
<VariableBox
path={path}
@ -208,7 +217,7 @@ export const ExpressionViewer: React.FC<Props> = ({
)}
</VariableBox>
);
case "lambdaDeclaration": {
case SquiggleValueTag.SvtDeclaration: {
return (
<VariableBox
path={path}
@ -224,21 +233,22 @@ export const ExpressionViewer: React.FC<Props> = ({
}}
>
{(settings) => (
<FunctionChart
fn={expression.value.fn}
chartSettings={getChartSettings(expression.value)}
distributionPlotSettings={settings.distributionPlotSettings}
height={settings.height}
environment={{
sampleCount: settings.environment.sampleCount / 10,
xyPointLength: settings.environment.xyPointLength / 10,
}}
/>
<div>NOT IMPLEMENTED IN 0.4 YET</div>
// <FunctionChart
// fn={expression.value.fn}
// chartSettings={getChartSettings(expression.value)}
// distributionPlotSettings={settings.distributionPlotSettings}
// height={settings.height}
// environment={{
// sampleCount: settings.environment.sampleCount / 10,
// xyPointLength: settings.environment.xyPointLength / 10,
// }}
// />
)}
</VariableBox>
);
}
case "module": {
case SquiggleValueTag.SvtModule: {
return (
<VariableList path={path} heading="Module">
{(_) =>
@ -256,7 +266,7 @@ export const ExpressionViewer: React.FC<Props> = ({
</VariableList>
);
}
case "record":
case SquiggleValueTag.SvtRecord:
const plot = makePlot(expression.value);
if (plot) {
return (
@ -308,11 +318,13 @@ export const ExpressionViewer: React.FC<Props> = ({
</VariableList>
);
}
case "array":
case SquiggleValueTag.SvtArray:
return (
<VariableList path={path} heading="Array">
{(_) =>
expression.value.map((r, i) => (
expression.value
.getValues()
.map((r, i) => (
<ExpressionViewer
key={i}
path={[...path, String(i)]}

View File

@ -1,7 +1,5 @@
export { SquiggleChart } from "./components/SquiggleChart";
export { SquiggleEditor, SquigglePartial } from "./components/SquiggleEditor";
export { SquiggleEditor } from "./components/SquiggleEditor";
export { SquigglePlayground } from "./components/SquigglePlayground";
export { SquiggleContainer } from "./components/SquiggleContainer";
export { SquiggleEditorWithImportedBindings } from "./components/SquiggleEditorWithImportedBindings";
export { mergeBindings } from "@quri/squiggle-lang";

View File

@ -1,3 +1,3 @@
export { useMaybeControlledValue } from "./useMaybeControlledValue";
export { useSquiggle, useSquigglePartial } from "./useSquiggle";
export { useSquiggle } from "./useSquiggle";
export { useRunnerState } from "./useRunnerState";

View File

@ -1,34 +1,25 @@
import {
bindings,
environment,
jsImports,
run,
runPartial,
} from "@quri/squiggle-lang";
import { environment, run, SquiggleValue } from "@quri/squiggle-lang";
import { useEffect, useMemo } from "react";
type SquiggleArgs<T extends ReturnType<typeof run | typeof runPartial>> = {
type SquiggleArgs = {
code: string;
executionId?: number;
bindings?: bindings;
jsImports?: jsImports;
// jsImports?: jsImports;
environment?: environment;
onChange?: (expr: Extract<T, { tag: "Ok" }>["value"] | undefined) => void;
onChange?: (expr: SquiggleValue | undefined) => void;
};
const useSquiggleAny = <T extends ReturnType<typeof run | typeof runPartial>>(
args: SquiggleArgs<T>,
f: (...args: Parameters<typeof run>) => T
) => {
const result: T = useMemo<T>(
() => f(args.code, args.bindings, args.environment, args.jsImports),
export const useSquiggle = (args: SquiggleArgs) => {
const result = useMemo(
() => {
const { result } = run(args.code, { environment: args.environment });
return result;
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[
f,
args.code,
args.bindings,
args.environment,
args.jsImports,
// args.environment,
// args.jsImports,
args.executionId,
]
);
@ -41,13 +32,3 @@ const useSquiggleAny = <T extends ReturnType<typeof run | typeof runPartial>>(
return result;
};
export const useSquigglePartial = (
args: SquiggleArgs<ReturnType<typeof runPartial>>
) => {
return useSquiggleAny(args, runPartial);
};
export const useSquiggle = (args: SquiggleArgs<ReturnType<typeof run>>) => {
return useSquiggleAny(args, run);
};

View File

@ -1,5 +1,5 @@
import * as yup from "yup";
import { Distribution, result, squiggleExpression } from "@quri/squiggle-lang";
import { Distribution, result, SquiggleRecord } from "@quri/squiggle-lang";
export type LabeledDistribution = {
name: string;
@ -53,9 +53,7 @@ const schema = yup
}),
});
export function parsePlot(record: {
[key: string]: squiggleExpression;
}): result<Plot, string> {
export function parsePlot(record: SquiggleRecord): result<Plot, string> {
try {
const plotRecord = schema.validateSync(record);
return ok({

View File

@ -1,10 +1,6 @@
import {
Distribution,
resultMap,
defaultBindings,
mergeBindings,
} from "../../src/js/index";
import { testRun, testRunPartial } from "./TestHelpers";
import { Project, SquiggleValue } from "../../src/js";
import { NumberValue } from "../../src/js/SquiggleValue";
import { failDefault, testRun } from "./TestHelpers";
function Ok<b>(x: b) {
return { tag: "Ok", value: x };
@ -12,150 +8,175 @@ function Ok<b>(x: b) {
describe("Simple calculations and results", () => {
test("mean(normal(5,2))", () => {
expect(testRun("mean(normal(5,2))")).toEqual({
tag: "number",
value: 5,
});
const result = testRun("mean(normal(5,2))"); // FIXME
expect(result.tag).toEqual("Number");
switch (result.tag) {
case "Number":
expect(result.value()).toEqual(5);
break;
default:
fail();
}
// tag: "number",
// value: 5,
// });
});
test("10+10", () => {
let foo = testRun("10 + 10");
expect(foo).toEqual({ tag: "number", value: 20 });
});
});
describe("Log function", () => {
test("log(1) = 0", () => {
let foo = testRun("log(1)");
expect(foo).toEqual({ tag: "number", value: 0 });
let result = testRun("10 + 10") as NumberValue;
expect(result.tag).toEqual("Number");
switch (result.tag) {
case "Number":
expect(result.value()).toEqual(20);
break;
default:
fail();
}
});
});
// describe("Log function", () => {
// test("log(1) = 0", () => {
// let foo = testRun("log(1)");
// expect(foo).toEqual({ tag: "number", value: 0 });
// });
// });
describe("Array", () => {
test("nested Array", () => {
expect(testRun("[[1]]")).toEqual({
tag: "array",
value: [
{
tag: "array",
value: [
{
tag: "number",
value: 1,
},
],
},
],
});
});
});
// describe("Array", () => {
// test("nested Array", () => {
// expect(testRun("[[1]]")).toEqual({
// tag: "array",
// value: [
// {
// tag: "array",
// value: [
// {
// tag: "number",
// value: 1,
// },
// ],
// },
// ],
// });
// });
// });
describe("Record", () => {
test("Return record", () => {
expect(testRun("{a: 1}")).toEqual({
tag: "record",
value: {
a: {
tag: "number",
value: 1,
},
},
});
});
});
// describe("Record", () => {
// test("Return record", () => {
// expect(testRun("{a: 1}")).toEqual({
// tag: "record",
// value: {
// a: {
// tag: "number",
// value: 1,
// },
// },
// });
// });
// });
describe("Partials", () => {
test("Can pass variables between partials and cells", () => {
let bindings = testRunPartial(`x = 5`);
let bindings2 = testRunPartial(`y = x + 2`, bindings);
expect(testRun(`y + 3`, bindings2)).toEqual({
tag: "number",
value: 10,
});
});
test("Can merge bindings from three partials", () => {
let bindings1 = testRunPartial(`x = 1`);
let bindings2 = testRunPartial(`y = 2`);
let bindings3 = testRunPartial(`z = 3`);
expect(
testRun(`x + y + z`, mergeBindings([bindings1, bindings2, bindings3]))
).toEqual({
tag: "number",
value: 6,
});
});
});
// describe("Partials", () => {
// test("Can pass variables between partials and cells", () => {
// const project = Project.create();
// project.setSource("p1", "x = 5");
// project.setSource("p2", "y = x + 2");
// project.setSource("main", "y + 3");
// project.run("main");
// const result = project.getResult("main");
// expect(result.tag).toEqual("Ok");
// expect(result.value).toBeInstanceOf(SquiggleValue);
// expect(result.value).toHaveProperty("tag", "number");
// failDefault(); // FIXME
// // let bindings = testRunPartial(`x = 5`);
// // let bindings2 = testRunPartial(`y = x + 2`, bindings);
// // expect(testRun(`y + 3`, bindings2)).toEqual({
// // tag: "number",
// // value: 10,
// // });
// });
// test("Can merge bindings from three partials", () => {
// let bindings1 = testRunPartial(`x = 1`);
// let bindings2 = testRunPartial(`y = 2`);
// let bindings3 = testRunPartial(`z = 3`);
// expect(
// testRun(`x + y + z`, mergeBindings([bindings1, bindings2, bindings3]))
// ).toEqual({
// tag: "number",
// value: 6,
// });
// });
// });
describe("JS Imports", () => {
test("Can pass parameters into partials and cells", () => {
let bindings = testRunPartial(`y = $x + 2`, defaultBindings, { x: 1 });
let bindings2 = testRunPartial(`z = y + $a`, bindings, { a: 3 });
expect(testRun(`z`, bindings2)).toEqual({
tag: "number",
value: 6,
});
});
test("Complicated deep parameters", () => {
expect(
testRun(`$x.y[0][0].w + $x.z + $u.v`, defaultBindings, {
x: { y: [[{ w: 1 }]], z: 2 },
u: { v: 3 },
})
).toEqual({
tag: "number",
value: 6,
});
});
});
// describe("JS Imports", () => {
// test("Can pass parameters into partials and cells", () => {
// let bindings = testRunPartial(`y = $x + 2`, defaultBindings, { x: 1 });
// let bindings2 = testRunPartial(`z = y + $a`, bindings, { a: 3 });
// expect(testRun(`z`, bindings2)).toEqual({
// tag: "number",
// value: 6,
// });
// });
// test("Complicated deep parameters", () => {
// expect(
// testRun(`$x.y[0][0].w + $x.z + $u.v`, defaultBindings, {
// x: { y: [[{ w: 1 }]], z: 2 },
// u: { v: 3 },
// })
// ).toEqual({
// tag: "number",
// value: 6,
// });
// });
// });
describe("Distribution", () => {
//It's important that sampleCount is less than 9. If it's more, than that will create randomness
//Also, note, the value should be created using makeSampleSetDist() later on.
let env = { sampleCount: 8, xyPointLength: 100 };
let dist1Samples = [3, 4, 5, 6, 6, 7, 10, 15, 30];
let dist1SampleCount = dist1Samples.length;
let dist = new Distribution(
{ tag: "SampleSet", value: [3, 4, 5, 6, 6, 7, 10, 15, 30] },
env
);
let dist2 = new Distribution(
{ tag: "SampleSet", value: [20, 22, 24, 29, 30, 35, 38, 44, 52] },
env
);
// describe("Distribution", () => {
// //It's important that sampleCount is less than 9. If it's more, than that will create randomness
// //Also, note, the value should be created using makeSampleSetDist() later on.
// let env = { sampleCount: 8, xyPointLength: 100 };
// let dist1Samples = [3, 4, 5, 6, 6, 7, 10, 15, 30];
// let dist1SampleCount = dist1Samples.length;
// let dist = new Distribution(
// { tag: "SampleSet", value: [3, 4, 5, 6, 6, 7, 10, 15, 30] },
// env
// );
// let dist2 = new Distribution(
// { tag: "SampleSet", value: [20, 22, 24, 29, 30, 35, 38, 44, 52] },
// env
// );
test("mean", () => {
expect(dist.mean().value).toBeCloseTo(9.5555555);
});
test("pdf", () => {
expect(dist.pdf(5.0).value).toBeCloseTo(0.10499097598222966, 1);
});
test("cdf", () => {
expect(dist.cdf(5.0).value).toBeCloseTo(
dist1Samples.filter((x) => x <= 5).length / dist1SampleCount,
1
);
});
test("inv", () => {
expect(dist.inv(0.5).value).toBeCloseTo(6);
});
test("toPointSet", () => {
expect(
resultMap(dist.toPointSet(), (r: Distribution) => r.toString())
).toEqual(Ok("Point Set Distribution"));
});
test("toSparkline", () => {
expect(dist.toSparkline(20).value).toEqual("▁▁▃▇█▇▄▂▂▂▁▁▁▁▁▂▂▁▁▁");
});
test("algebraicAdd", () => {
expect(
resultMap(dist.algebraicAdd(dist2), (r: Distribution) =>
r.toSparkline(20)
).value
).toEqual(Ok("▁▁▂▄▆████▇▆▄▄▃▃▃▂▁▁▁"));
});
test("pointwiseAdd", () => {
expect(
resultMap(dist.pointwiseAdd(dist2), (r: Distribution) =>
r.toSparkline(20)
).value
).toEqual(Ok("▁▂██▃▃▃▃▄▅▄▃▃▂▂▂▁▁▁▁"));
});
});
// test("mean", () => {
// expect(dist.mean().value).toBeCloseTo(9.5555555);
// });
// test("pdf", () => {
// expect(dist.pdf(5.0).value).toBeCloseTo(0.10499097598222966, 1);
// });
// test("cdf", () => {
// expect(dist.cdf(5.0).value).toBeCloseTo(
// dist1Samples.filter((x) => x <= 5).length / dist1SampleCount,
// 1
// );
// });
// test("inv", () => {
// expect(dist.inv(0.5).value).toBeCloseTo(6);
// });
// test("toPointSet", () => {
// expect(
// resultMap(dist.toPointSet(), (r: Distribution) => r.toString())
// ).toEqual(Ok("Point Set Distribution"));
// });
// test("toSparkline", () => {
// expect(dist.toSparkline(20).value).toEqual("▁▁▃▇█▇▄▂▂▂▁▁▁▁▁▂▂▁▁▁");
// });
// test("algebraicAdd", () => {
// expect(
// resultMap(dist.algebraicAdd(dist2), (r: Distribution) =>
// r.toSparkline(20)
// ).value
// ).toEqual(Ok("▁▁▂▄▆████▇▆▄▄▃▃▃▂▁▁▁"));
// });
// test("pointwiseAdd", () => {
// expect(
// resultMap(dist.pointwiseAdd(dist2), (r: Distribution) =>
// r.toSparkline(20)
// ).value
// ).toEqual(Ok("▁▂██▃▃▃▃▄▅▄▃▃▂▂▂▁▁▁▁"));
// });
// });

View File

@ -1,60 +1,21 @@
import {
run,
runPartial,
bindings,
squiggleExpression,
errorValueToString,
defaultImports,
defaultBindings,
jsImports,
} from "../../src/js/index";
import { run, SquiggleValue } from "../../src/js/index";
export function testRun(
x: string,
bindings: bindings = defaultBindings,
imports: jsImports = defaultImports
): squiggleExpression {
let squiggleResult = run(
x,
bindings,
{
sampleCount: 1000,
xyPointLength: 100,
},
imports
);
if (squiggleResult.tag === "Ok") {
return squiggleResult.value;
export function testRun(x: string) {
const { result, bindings } = run(x); // FIXME - set environment
// x,
// bindings,
// {
// sampleCount: 1000,
// xyPointLength: 100,
// },
// imports
// );
if (result.tag === "Ok") {
return result.value;
} else {
throw new Error(
`Expected squiggle expression to evaluate but got error: ${errorValueToString(
squiggleResult.value
)}`
);
}
}
export function testRunPartial(
x: string,
bindings: bindings = defaultBindings,
imports: jsImports = defaultImports
): bindings {
let squiggleResult = runPartial(
x,
bindings,
{
sampleCount: 1000,
xyPointLength: 100,
},
imports
);
if (squiggleResult.tag === "Ok") {
return squiggleResult.value;
} else {
throw new Error(
`Expected squiggle expression to evaluate but got error: ${errorValueToString(
squiggleResult.value
)}`
`Expected squiggle expression to evaluate but got error: ${result.value}`
);
}
}

View File

@ -0,0 +1,93 @@
import * as RSDistribution from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution.gen";
import { distributionTag as Tag } from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_tag";
import { DistributionError } from "./DistributionError";
import { wrapPointSetDist } from "./PointSetDist";
import { resultMap2 } from "./types";
type T = RSDistribution.distribution;
export { Tag };
export const wrapDistribution = (value: T): Distribution => {
const tag = RSDistribution.getTag(value);
return new tagToClass[tag](value);
};
abstract class AbstractDistribution {
abstract tag: Tag;
_value: T;
constructor(value: T) {
this._value = value;
}
pointSet() {
const env: any = "TODO";
const innerResult = RSDistribution.toPointSet(this._value, env);
return resultMap2(
innerResult,
wrapPointSetDist,
(v: RSDistribution.distributionError) => new DistributionError(v)
);
}
toString() {
RSDistribution.toString(this._value);
}
mean() {
return RSDistribution.mean(this._value);
}
inv(n: number) {
return RSDistribution.inv(this._value, n);
}
stdev() {
return RSDistribution.stdev(this._value);
}
}
const valueMethod = <IR>(
_this: AbstractDistribution,
rsMethod: (v: T) => IR | null | undefined
) => {
const value = rsMethod(_this._value);
if (!value) throw new Error("Internal casting error");
return value;
};
export class PointSetDistribution extends AbstractDistribution {
tag = Tag.DtPointSet;
value() {
return valueMethod(this, RSDistribution.getPointSet);
}
}
export class SampleSetDistribution extends AbstractDistribution {
tag = Tag.DtSampleSet;
value() {
return valueMethod(this, RSDistribution.getSampleSet);
}
}
export class SymbolicDistribution extends AbstractDistribution {
tag = Tag.DtSymbolic;
value() {
return valueMethod(this, RSDistribution.getSymbolic);
}
}
const tagToClass = {
[Tag.DtPointSet]: PointSetDistribution,
[Tag.DtSampleSet]: SampleSetDistribution,
[Tag.DtSymbolic]: SymbolicDistribution,
} as const;
export type Distribution =
| PointSetDistribution
| SampleSetDistribution
| SymbolicDistribution;

View File

@ -0,0 +1,15 @@
import * as RSDistributionError from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Error.gen";
type T = RSDistributionError.distributionError;
export class DistributionError {
_value: T;
constructor(_value: T) {
this._value = _value;
}
toString() {
return RSDistributionError.toString(this._value);
}
}

View File

@ -0,0 +1,13 @@
import * as RSErrorValue from "../rescript/ForTS/ForTS_Reducer_ErrorValue.gen";
export class ErrorValue {
_value: RSErrorValue.reducerErrorValue;
constructor(_value: RSErrorValue.reducerErrorValue) {
this._value = _value;
}
toString() {
return RSErrorValue.toString(this._value);
}
}

View File

@ -0,0 +1,11 @@
import * as RSLambda from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Lambda.gen";
type T = RSLambda.squiggleValue_Lambda;
export class Lambda {
_value: T;
constructor(_value: T) {
this._value = _value;
}
}

View File

@ -0,0 +1,11 @@
import * as RSDeclaration from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Declaration.gen";
type T = RSDeclaration.squiggleValue_Declaration;
export class LambdaDeclaration {
_value: T;
constructor(_value: T) {
this._value = _value;
}
}

View File

@ -0,0 +1,9 @@
import * as RSModuleValue from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Module.gen";
export class NameSpace {
_value: RSModuleValue.squiggleValue_Module;
constructor(_value: RSModuleValue.squiggleValue_Module) {
this._value = _value;
}
}

View File

@ -0,0 +1,103 @@
import * as _ from "lodash";
import * as RSPointSetDist from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution.gen";
import { pointSetDistributionTag as Tag } from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_PointSetDistribution_tag";
type T = RSPointSetDist.pointSetDistribution;
export type point = { x: number; y: number };
type shape = {
continuous: point[];
discrete: point[];
};
const shapePoints = (
x: RSPointSetDist.continuousShape | RSPointSetDist.discreteShape
): point[] => {
let xs = x.xyShape.xs;
let ys = x.xyShape.ys;
return _.zipWith(xs, ys, (x, y) => ({ x, y }));
};
export const wrapPointSetDist = (value: T) => {
const tag = RSPointSetDist.getTag(value);
return new tagToClass[tag](value);
};
abstract class AbstractPointSetDist {
_value: T;
constructor(_value: T) {
this._value = _value;
}
abstract asShape(): shape;
}
const valueMethod = <IR>(
_this: AbstractPointSetDist,
rsMethod: (v: T) => IR | null | undefined
) => {
const value = rsMethod(_this._value);
if (!value) throw new Error("Internal casting error");
return value;
};
export class MixedPointSetDist extends AbstractPointSetDist {
tag = Tag.PstMixed as const;
get value(): RSPointSetDist.mixedShape {
return valueMethod(this, RSPointSetDist.getMixed);
}
asShape() {
const v = this.value;
return {
discrete: shapePoints(v.discrete),
continuous: shapePoints(v.continuous),
};
}
}
export class DiscretePointSetDist extends AbstractPointSetDist {
tag = Tag.PstDiscrete as const;
get value(): RSPointSetDist.discreteShape {
return valueMethod(this, RSPointSetDist.getDiscrete);
}
asShape() {
const v = this.value;
return {
discrete: shapePoints(v),
continuous: [],
};
}
}
export class ContinuousPointSetDist extends AbstractPointSetDist {
tag = Tag.PstContinuous as const;
get value(): RSPointSetDist.continuousShape {
return valueMethod(this, RSPointSetDist.getContinues);
}
asShape() {
const v = this.value;
return {
discrete: [],
continuous: shapePoints(v),
};
}
}
const tagToClass = {
[Tag.PstMixed]: MixedPointSetDist,
[Tag.PstDiscrete]: DiscretePointSetDist,
[Tag.PstContinuous]: ContinuousPointSetDist,
} as const;
export type PointSetDist =
| MixedPointSetDist
| DiscretePointSetDist
| ContinuousPointSetDist;

View File

@ -0,0 +1,112 @@
import * as RSProject from "../rescript/ForTS/ForTS_ReducerProject.gen";
import { reducerErrorValue } from "../rescript/ForTS/ForTS_Reducer_ErrorValue.gen";
import { environment } from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_Environment.gen";
import { ErrorValue } from "./ErrorValue";
import { NameSpace as NameSpace } from "./NameSpace";
import { wrapSquiggleValue } from "./SquiggleValue";
import { resultMap2 } from "./types";
export class Project {
_value: RSProject.reducerProject;
constructor(_value: RSProject.reducerProject) {
this._value = _value;
}
static create() {
return new Project(RSProject.createProject());
}
getSourceIds() {
return RSProject.getSourceIds(this._value);
}
setSource(sourceId: string, value: string) {
return RSProject.setSource(this._value, sourceId, value);
}
getSource(sourceId: string) {
return RSProject.getSource(this._value, sourceId);
}
touchSource(sourceId: string) {
return RSProject.touchSource(this._value, sourceId);
}
clean(sourceId: string) {
return RSProject.clean(this._value, sourceId);
}
cleanAll() {
return RSProject.cleanAll(this._value);
}
cleanResults(sourceId: string) {
return RSProject.cleanResults(this._value, sourceId);
}
cleanAllResults() {
return RSProject.cleanAllResults(this._value);
}
getIncludes(sourceId: string) {
return resultMap2(
RSProject.getIncludes(this._value, sourceId),
(a) => a,
(v: reducerErrorValue) => new ErrorValue(v)
);
}
getContinues(sourceId: string) {
return RSProject.getContinues(this._value, sourceId);
}
setContinues(sourceId: string, continues: string[]) {
return RSProject.setContinues(this._value, sourceId, continues);
}
getDependencies(sourceId: string) {
return RSProject.getDependencies(this._value, sourceId);
}
getDependents(sourceId: string) {
return RSProject.getDependents(this._value, sourceId);
}
getRunOrder() {
return RSProject.getRunOrder(this._value);
}
getRunOrderFor(sourceId: string) {
return RSProject.getRunOrderFor(this._value, sourceId);
}
parseIncludes(sourceId: string) {
return RSProject.parseIncludes(this._value, sourceId);
}
run(sourceId: string) {
return RSProject.run(this._value, sourceId);
}
runAll() {
return RSProject.runAll(this._value);
}
getBindings(sourceId: string) {
return new NameSpace(RSProject.getBindings(this._value, sourceId));
}
getResult(sourceId: string) {
const innerResult = RSProject.getResult(this._value, sourceId);
return resultMap2(
innerResult,
wrapSquiggleValue,
(v: reducerErrorValue) => new ErrorValue(v)
);
}
setEnvironment(environment: environment) {
RSProject.setEnvironment(this._value, environment);
}
}

View File

@ -0,0 +1,18 @@
import * as RSRecord from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Record.gen";
import { AbstractSquiggleValue, wrapSquiggleValue } from "./SquiggleValue";
type T = RSRecord.squiggleValue_Record;
export class Record {
_value: T;
constructor(_value: T) {
this._value = _value;
}
entries() {
return RSRecord.getKeyValuePairs(this._value).map(
([k, v]) => [k, wrapSquiggleValue(v)] as const
);
}
}

View File

@ -0,0 +1,16 @@
import * as RSArray from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Array.gen";
import { AbstractSquiggleValue, wrapSquiggleValue } from "./SquiggleValue";
type T = RSArray.squiggleValue_Array;
export class SquiggleArray {
_value: T;
constructor(_value: T) {
this._value = _value;
}
getValues() {
return RSArray.getValues(this._value).map(wrapSquiggleValue);
}
}

View File

@ -0,0 +1,212 @@
import * as RSSquiggleValue from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue.gen";
import { squiggleValueTag as Tag } from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_tag";
import { Distribution, wrapDistribution } from "./Distribution";
import { Lambda } from "./Lambda";
import { LambdaDeclaration } from "./LambdaDeclaration";
import { NameSpace } from "./NameSpace";
import { Record } from "./Record";
import { SquiggleArray } from "./SquiggleArray";
import { Type } from "./Type";
export { Tag };
type T = RSSquiggleValue.squiggleValue;
export const wrapSquiggleValue = (value: T): SquiggleValue => {
const tag = RSSquiggleValue.getTag(value);
return new tagToClass[tag](value);
};
export abstract class AbstractSquiggleValue {
abstract tag: Tag;
_value: T;
constructor(value: T) {
this._value = value;
}
}
const valueMethod = <IR>(
_this: AbstractSquiggleValue,
rsMethod: (v: T) => IR | null | undefined
) => {
const value = rsMethod(_this._value);
if (!value) throw new Error("Internal casting error");
return value;
};
export class ArrayValue extends AbstractSquiggleValue {
tag = Tag.SvtArray as const;
get value() {
return new SquiggleArray(valueMethod(this, RSSquiggleValue.getArray));
}
}
export class ArrayStringValue extends AbstractSquiggleValue {
tag = Tag.SvtArrayString as const;
get value() {
return valueMethod(this, RSSquiggleValue.getArrayString);
}
}
export class BoolValue extends AbstractSquiggleValue {
tag = Tag.SvtBool as const;
get value() {
return valueMethod(this, RSSquiggleValue.getBool);
}
}
export class CallValue extends AbstractSquiggleValue {
tag = Tag.SvtCall as const;
get value() {
return valueMethod(this, RSSquiggleValue.getCall);
}
}
export class DateValue extends AbstractSquiggleValue {
tag = Tag.SvtDate as const;
get value() {
return valueMethod(this, RSSquiggleValue.getDate);
}
}
export class DeclarationValue extends AbstractSquiggleValue {
tag = Tag.SvtDeclaration as const;
get value() {
return new LambdaDeclaration(
valueMethod(this, RSSquiggleValue.getDeclaration)
);
}
}
export class DistributionValue extends AbstractSquiggleValue {
tag = Tag.SvtDistribution as const;
get value() {
return wrapDistribution(valueMethod(this, RSSquiggleValue.getDistribution));
}
}
export class LambdaValue extends AbstractSquiggleValue {
tag = Tag.SvtLambda as const;
get value() {
return new Lambda(valueMethod(this, RSSquiggleValue.getLambda));
}
}
export class ModuleValue extends AbstractSquiggleValue {
tag = Tag.SvtModule as const;
get value() {
return new NameSpace(valueMethod(this, RSSquiggleValue.getModule));
}
}
export class NumberValue extends AbstractSquiggleValue {
tag = Tag.SvtNumber as const;
get value() {
return valueMethod(this, RSSquiggleValue.getNumber);
}
}
export class RecordValue extends AbstractSquiggleValue {
tag = Tag.SvtRecord as const;
get value() {
return new Record(valueMethod(this, RSSquiggleValue.getRecord));
}
}
export class StringValue extends AbstractSquiggleValue {
tag = Tag.SvtString as const;
get value(): string {
return valueMethod(this, RSSquiggleValue.getString);
}
}
export class SymbolValue extends AbstractSquiggleValue {
tag = Tag.SvtSymbol as const;
get value(): string {
return valueMethod(this, RSSquiggleValue.getSymbol);
}
}
export class TimeDurationValue extends AbstractSquiggleValue {
tag = Tag.SvtTimeDuration as const;
get value() {
return valueMethod(this, RSSquiggleValue.getTimeDuration);
}
}
export class TypeValue extends AbstractSquiggleValue {
tag = Tag.SvtType as const;
get value() {
return new Type(valueMethod(this, RSSquiggleValue.getType));
}
}
export class TypeIdentifierValue extends AbstractSquiggleValue {
tag = Tag.SvtTypeIdentifier as const;
get value() {
return valueMethod(this, RSSquiggleValue.getTypeIdentifier);
}
}
export class VoidValue extends AbstractSquiggleValue {
tag = Tag.SvtVoid as const;
}
const tagToClass = {
[Tag.SvtArray]: ArrayValue,
[Tag.SvtArrayString]: ArrayStringValue,
[Tag.SvtBool]: BoolValue,
[Tag.SvtCall]: CallValue,
[Tag.SvtDate]: DateValue,
[Tag.SvtDeclaration]: DeclarationValue,
[Tag.SvtDistribution]: DistributionValue,
[Tag.SvtLambda]: LambdaValue,
[Tag.SvtModule]: ModuleValue,
[Tag.SvtNumber]: NumberValue,
[Tag.SvtRecord]: RecordValue,
[Tag.SvtString]: StringValue,
[Tag.SvtSymbol]: SymbolValue,
[Tag.SvtTimeDuration]: TimeDurationValue,
[Tag.SvtType]: TypeValue,
[Tag.SvtTypeIdentifier]: TypeIdentifierValue,
[Tag.SvtVoid]: VoidValue,
} as const;
// FIXME
// type AnySquiggleValue = typeof tagToClass[keyof typeof tagToClass];
export type SquiggleValue =
| ArrayValue
| ArrayStringValue
| BoolValue
| CallValue
| DateValue
| DeclarationValue
| DistributionValue
| LambdaValue
| ModuleValue
| NumberValue
| RecordValue
| StringValue
| SymbolValue
| TimeDurationValue
| TypeValue
| TypeIdentifierValue
| VoidValue;

View File

@ -0,0 +1,11 @@
import * as RSType from "../rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_Type.gen";
type T = RSType.squiggleValue_Type;
export class Type {
_value: T;
constructor(_value: T) {
this._value = _value;
}
}

View File

@ -1,252 +1,93 @@
import * as _ from "lodash";
import {
genericDist,
continuousShape,
discreteShape,
environment,
distributionError,
toPointSet,
distributionErrorToString,
} from "../rescript/TypescriptInterface.gen";
import { result, resultMap, Ok } from "./types";
import {
Constructors_mean,
Constructors_stdev,
Constructors_sample,
Constructors_pdf,
Constructors_cdf,
Constructors_inv,
Constructors_normalize,
Constructors_isNormalized,
Constructors_toPointSet,
Constructors_toSampleSet,
Constructors_truncate,
Constructors_inspect,
Constructors_toString,
Constructors_toSparkline,
Constructors_algebraicAdd,
Constructors_algebraicMultiply,
Constructors_algebraicDivide,
Constructors_algebraicSubtract,
Constructors_algebraicLogarithm,
Constructors_algebraicPower,
Constructors_pointwiseAdd,
Constructors_pointwiseMultiply,
Constructors_pointwiseDivide,
Constructors_pointwiseSubtract,
Constructors_pointwiseLogarithm,
Constructors_pointwisePower,
} from "../rescript/Distributions/DistributionOperation.gen";
import * as RSDistribution from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution.gen";
import { distributionTag as Tag } from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution_tag";
import { DistributionError } from "./DistributionError";
import { wrapPointSetDist } from "./PointSetDist";
import { resultMap2 } from "./types";
export type point = { x: number; y: number };
type T = RSDistribution.distribution;
export { Tag };
function shapePoints(x: continuousShape | discreteShape): point[] {
let xs = x.xyShape.xs;
let ys = x.xyShape.ys;
return _.zipWith(xs, ys, (x, y) => ({ x, y }));
}
export type shape = {
continuous: point[];
discrete: point[];
export const wrapDistribution = (value: T): Distribution => {
const tag = RSDistribution.getTag(value);
return new tagToClass[tag](value);
};
export class Distribution {
t: genericDist;
env: environment;
abstract class AbstractDistribution {
abstract tag: Tag;
_value: T;
constructor(t: genericDist, env: environment) {
this.t = t;
this.env = env;
return this;
constructor(value: T) {
this._value = value;
}
mapResultDist(
r: result<genericDist, distributionError>
): result<Distribution, distributionError> {
return resultMap(r, (v: genericDist) => new Distribution(v, this.env));
}
mean(): result<number, distributionError> {
return Constructors_mean({ env: this.env }, this.t);
}
stdev(): result<number, distributionError> {
return Constructors_stdev({ env: this.env }, this.t);
}
sample(): result<number, distributionError> {
return Constructors_sample({ env: this.env }, this.t);
}
pdf(n: number): result<number, distributionError> {
return Constructors_pdf({ env: this.env }, this.t, n);
}
cdf(n: number): result<number, distributionError> {
return Constructors_cdf({ env: this.env }, this.t, n);
}
inv(n: number): result<number, distributionError> {
return Constructors_inv({ env: this.env }, this.t, n);
}
isNormalized(): result<boolean, distributionError> {
return Constructors_isNormalized({ env: this.env }, this.t);
}
normalize(): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_normalize({ env: this.env }, this.t)
pointSet() {
const env: any = "TODO";
const innerResult = RSDistribution.toPointSet(this._value, env);
return resultMap2(
innerResult,
wrapPointSetDist,
(v: RSDistribution.distributionError) => new DistributionError(v)
);
}
type() {
return this.t.tag;
toString() {
RSDistribution.toString(this._value);
}
pointSet(): result<shape, distributionError> {
let pointSet = toPointSet(
this.t,
{
xyPointLength: this.env.xyPointLength,
sampleCount: this.env.sampleCount,
},
undefined
);
if (pointSet.tag === "Ok") {
let distribution = pointSet.value;
if (distribution.tag === "Continuous") {
return Ok({
continuous: shapePoints(distribution.value),
discrete: [],
});
} else if (distribution.tag === "Discrete") {
return Ok({
discrete: shapePoints(distribution.value),
continuous: [],
});
} else {
return Ok({
discrete: shapePoints(distribution.value.discrete),
continuous: shapePoints(distribution.value.continuous),
});
}
} else {
return pointSet;
}
mean() {
return RSDistribution.mean(this._value);
}
toPointSet(): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_toPointSet({ env: this.env }, this.t)
);
inv(n: number) {
return RSDistribution.inv(this._value, n);
}
toSampleSet(n: number): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_toSampleSet({ env: this.env }, this.t, n)
);
}
truncate(
left: number,
right: number
): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_truncate({ env: this.env }, this.t, left, right)
);
}
inspect(): result<Distribution, distributionError> {
return this.mapResultDist(Constructors_inspect({ env: this.env }, this.t));
}
toString(): string {
let result = Constructors_toString({ env: this.env }, this.t);
if (result.tag === "Ok") {
return result.value;
} else {
return distributionErrorToString(result.value);
}
}
toSparkline(n: number): result<string, distributionError> {
return Constructors_toSparkline({ env: this.env }, this.t, n);
}
algebraicAdd(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicAdd({ env: this.env }, this.t, d2.t)
);
}
algebraicMultiply(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicMultiply({ env: this.env }, this.t, d2.t)
);
}
algebraicDivide(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicDivide({ env: this.env }, this.t, d2.t)
);
}
algebraicSubtract(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicSubtract({ env: this.env }, this.t, d2.t)
);
}
algebraicLogarithm(
d2: Distribution
): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicLogarithm({ env: this.env }, this.t, d2.t)
);
}
algebraicPower(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_algebraicPower({ env: this.env }, this.t, d2.t)
);
}
pointwiseAdd(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwiseAdd({ env: this.env }, this.t, d2.t)
);
}
pointwiseMultiply(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwiseMultiply({ env: this.env }, this.t, d2.t)
);
}
pointwiseDivide(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwiseDivide({ env: this.env }, this.t, d2.t)
);
}
pointwiseSubtract(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwiseSubtract({ env: this.env }, this.t, d2.t)
);
}
pointwiseLogarithm(
d2: Distribution
): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwiseLogarithm({ env: this.env }, this.t, d2.t)
);
}
pointwisePower(d2: Distribution): result<Distribution, distributionError> {
return this.mapResultDist(
Constructors_pointwisePower({ env: this.env }, this.t, d2.t)
);
stdev() {
return RSDistribution.stdev(this._value);
}
}
const valueMethod = <IR>(
_this: AbstractDistribution,
rsMethod: (v: T) => IR | null | undefined
) => {
const value = rsMethod(_this._value);
if (!value) throw new Error("Internal casting error");
return value;
};
export class PointSetDistribution extends AbstractDistribution {
tag = Tag.DtPointSet;
value() {
return valueMethod(this, RSDistribution.getPointSet);
}
}
export class SampleSetDistribution extends AbstractDistribution {
tag = Tag.DtSampleSet;
value() {
return valueMethod(this, RSDistribution.getSampleSet);
}
}
export class SymbolicDistribution extends AbstractDistribution {
tag = Tag.DtSymbolic;
value() {
return valueMethod(this, RSDistribution.getSymbolic);
}
}
const tagToClass = {
[Tag.DtPointSet]: PointSetDistribution,
[Tag.DtSampleSet]: SampleSetDistribution,
[Tag.DtSymbolic]: SymbolicDistribution,
} as const;
export type Distribution =
| PointSetDistribution
| SampleSetDistribution
| SymbolicDistribution;

View File

@ -10,54 +10,87 @@ Instead of a global function namespace we should use modules under ForTS directl
*/
import * as _ from "lodash";
import type {
environment,
expressionValue,
externalBindings,
errorValue,
} from "../rescript/TypescriptInterface.gen";
import {
defaultEnvironment,
evaluatePartialUsingExternalBindings,
evaluateUsingOptions,
foreignFunctionInterface,
} from "../rescript/TypescriptInterface.gen";
import { environment } from "../rescript/ForTS/ForTS_ReducerProject.gen";
import { Project } from "./Project";
import { SquiggleValue, Tag as SquiggleValueTag } from "./SquiggleValue";
export { result } from "../rescript/ForTS/ForTS_Result_tag";
export { Project, SquiggleValue };
export { Distribution, Tag as DistributionTag } from "./Distribution";
export { DistributionError } from "./DistributionError";
export { Record as SquiggleRecord } from "./Record";
export { SquiggleValueTag };
export {
makeSampleSetDist,
errorValueToString,
distributionErrorToString,
} from "../rescript/TypescriptInterface.gen";
export type {
distributionError,
declarationArg,
declaration,
} from "../rescript/TypescriptInterface.gen";
export type { errorValue, externalBindings as bindings, jsImports };
import {
jsValueToBinding,
jsValueToExpressionValue,
jsValue,
rescriptExport,
squiggleExpression,
convertRawToTypescript,
lambdaValue,
} from "./rescript_interop";
import { result, resultMap, tag, tagged } from "./types";
import { Distribution, shape } from "./distribution";
environment,
defaultEnvironment,
} from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution.gen";
export { ErrorValue } from "./ErrorValue";
export { resultMap } from "./types";
export { Distribution, resultMap, defaultEnvironment };
export type { result, shape, environment, lambdaValue, squiggleExpression };
// import * as _ from "lodash";
// import type {
// environment,
// expressionValue,
// externalBindings,
// errorValue,
// } from "../rescript/TypescriptInterface.gen";
// import {
// defaultEnvironment,
// evaluatePartialUsingExternalBindings,
// evaluateUsingOptions,
// foreignFunctionInterface,
// } from "../rescript/TypescriptInterface.gen";
// export {
// makeSampleSetDist,
// errorValueToString,
// distributionErrorToString,
// } from "../rescript/TypescriptInterface.gen";
// export type {
// distributionError,
// declarationArg,
// declaration,
// } from "../rescript/TypescriptInterface.gen";
// export type { errorValue, externalBindings as bindings, jsImports };
// import {
// jsValueToBinding,
// jsValueToExpressionValue,
// jsValue,
// rescriptExport,
// squiggleExpression,
// convertRawToTypescript,
// lambdaValue,
// } from "./rescript_interop";
// import { result, resultMap, tag, tagged } from "./types";
// import { Distribution, shape } from "./distribution";
export { parse } from "./parse";
// export { Distribution, resultMap, defaultEnvironment };
// export type { result, shape, environment, lambdaValue, squiggleExpression };
export let defaultSamplingInputs: environment = {
sampleCount: 10000,
xyPointLength: 10000,
};
// export { parse } from "./parse";
// export let defaultSamplingInputs: environment = {
// sampleCount: 10000,
// xyPointLength: 10000,
// };
/* Umur: All the functions below are invalid. ForTS_Reducer project is the new way to do this. */
export const run = (
code: string,
options?: {
environment?: environment;
}
) => {
const project = Project.create();
project.setSource("main", code);
if (options?.environment) {
project.setEnvironment(options.environment);
}
project.run("main");
const result = project.getResult("main");
const bindings = project.getBindings("main");
return { result, bindings };
};
// export function run(
// squiggleString: string,
// bindings?: externalBindings,

View File

@ -0,0 +1,252 @@
// import * as _ from "lodash";
// import {
// genericDist,
// continuousShape,
// discreteShape,
// environment,
// distributionError,
// toPointSet,
// distributionErrorToString,
// } from "../rescript/TypescriptInterface.gen";
// import { result, resultMap, Ok } from "./types";
// import {
// Constructors_mean,
// Constructors_stdev,
// Constructors_sample,
// Constructors_pdf,
// Constructors_cdf,
// Constructors_inv,
// Constructors_normalize,
// Constructors_isNormalized,
// Constructors_toPointSet,
// Constructors_toSampleSet,
// Constructors_truncate,
// Constructors_inspect,
// Constructors_toString,
// Constructors_toSparkline,
// Constructors_algebraicAdd,
// Constructors_algebraicMultiply,
// Constructors_algebraicDivide,
// Constructors_algebraicSubtract,
// Constructors_algebraicLogarithm,
// Constructors_algebraicPower,
// Constructors_pointwiseAdd,
// Constructors_pointwiseMultiply,
// Constructors_pointwiseDivide,
// Constructors_pointwiseSubtract,
// Constructors_pointwiseLogarithm,
// Constructors_pointwisePower,
// } from "../rescript/Distributions/DistributionOperation.gen";
// export type point = { x: number; y: number };
// function shapePoints(x: continuousShape | discreteShape): point[] {
// let xs = x.xyShape.xs;
// let ys = x.xyShape.ys;
// return _.zipWith(xs, ys, (x, y) => ({ x, y }));
// }
// export type shape = {
// continuous: point[];
// discrete: point[];
// };
// export class Distribution {
// t: genericDist;
// env: environment;
// constructor(t: genericDist, env: environment) {
// this.t = t;
// this.env = env;
// return this;
// }
// mapResultDist(
// r: result<genericDist, distributionError>
// ): result<Distribution, distributionError> {
// return resultMap(r, (v: genericDist) => new Distribution(v, this.env));
// }
// mean(): result<number, distributionError> {
// return Constructors_mean({ env: this.env }, this.t);
// }
// stdev(): result<number, distributionError> {
// return Constructors_stdev({ env: this.env }, this.t);
// }
// sample(): result<number, distributionError> {
// return Constructors_sample({ env: this.env }, this.t);
// }
// pdf(n: number): result<number, distributionError> {
// return Constructors_pdf({ env: this.env }, this.t, n);
// }
// cdf(n: number): result<number, distributionError> {
// return Constructors_cdf({ env: this.env }, this.t, n);
// }
// inv(n: number): result<number, distributionError> {
// return Constructors_inv({ env: this.env }, this.t, n);
// }
// isNormalized(): result<boolean, distributionError> {
// return Constructors_isNormalized({ env: this.env }, this.t);
// }
// normalize(): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_normalize({ env: this.env }, this.t)
// );
// }
// type() {
// return this.t.tag;
// }
// pointSet(): result<shape, distributionError> {
// let pointSet = toPointSet(
// this.t,
// {
// xyPointLength: this.env.xyPointLength,
// sampleCount: this.env.sampleCount,
// },
// undefined
// );
// if (pointSet.tag === "Ok") {
// let distribution = pointSet.value;
// if (distribution.tag === "Continuous") {
// return Ok({
// continuous: shapePoints(distribution.value),
// discrete: [],
// });
// } else if (distribution.tag === "Discrete") {
// return Ok({
// discrete: shapePoints(distribution.value),
// continuous: [],
// });
// } else {
// return Ok({
// discrete: shapePoints(distribution.value.discrete),
// continuous: shapePoints(distribution.value.continuous),
// });
// }
// } else {
// return pointSet;
// }
// }
// toPointSet(): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_toPointSet({ env: this.env }, this.t)
// );
// }
// toSampleSet(n: number): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_toSampleSet({ env: this.env }, this.t, n)
// );
// }
// truncate(
// left: number,
// right: number
// ): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_truncate({ env: this.env }, this.t, left, right)
// );
// }
// inspect(): result<Distribution, distributionError> {
// return this.mapResultDist(Constructors_inspect({ env: this.env }, this.t));
// }
// toString(): string {
// let result = Constructors_toString({ env: this.env }, this.t);
// if (result.tag === "Ok") {
// return result.value;
// } else {
// return distributionErrorToString(result.value);
// }
// }
// toSparkline(n: number): result<string, distributionError> {
// return Constructors_toSparkline({ env: this.env }, this.t, n);
// }
// algebraicAdd(d2: Distribution): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_algebraicAdd({ env: this.env }, this.t, d2.t)
// );
// }
// algebraicMultiply(d2: Distribution): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_algebraicMultiply({ env: this.env }, this.t, d2.t)
// );
// }
// algebraicDivide(d2: Distribution): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_algebraicDivide({ env: this.env }, this.t, d2.t)
// );
// }
// algebraicSubtract(d2: Distribution): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_algebraicSubtract({ env: this.env }, this.t, d2.t)
// );
// }
// algebraicLogarithm(
// d2: Distribution
// ): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_algebraicLogarithm({ env: this.env }, this.t, d2.t)
// );
// }
// algebraicPower(d2: Distribution): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_algebraicPower({ env: this.env }, this.t, d2.t)
// );
// }
// pointwiseAdd(d2: Distribution): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_pointwiseAdd({ env: this.env }, this.t, d2.t)
// );
// }
// pointwiseMultiply(d2: Distribution): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_pointwiseMultiply({ env: this.env }, this.t, d2.t)
// );
// }
// pointwiseDivide(d2: Distribution): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_pointwiseDivide({ env: this.env }, this.t, d2.t)
// );
// }
// pointwiseSubtract(d2: Distribution): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_pointwiseSubtract({ env: this.env }, this.t, d2.t)
// );
// }
// pointwiseLogarithm(
// d2: Distribution
// ): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_pointwiseLogarithm({ env: this.env }, this.t, d2.t)
// );
// }
// pointwisePower(d2: Distribution): result<Distribution, distributionError> {
// return this.mapResultDist(
// Constructors_pointwisePower({ env: this.env }, this.t, d2.t)
// );
// }
// }

View File

@ -1,23 +1,23 @@
import {
errorValue,
parse as parseRescript,
} from "../rescript/TypescriptInterface.gen";
import { result } from "./types";
import { AnyPeggyNode } from "../rescript/Reducer/Reducer_Peggy/helpers";
// import {
// errorValue,
// parse as parseRescript,
// } from "../rescript/TypescriptInterface.gen";
// import { result } from "./types";
// import { AnyPeggyNode } from "../rescript/Reducer/Reducer_Peggy/helpers";
export function parse(
squiggleString: string
): result<AnyPeggyNode, Extract<errorValue, { tag: "RESyntaxError" }>> {
const maybeExpression = parseRescript(squiggleString);
if (maybeExpression.tag === "Ok") {
return { tag: "Ok", value: maybeExpression.value as AnyPeggyNode };
} else {
if (
typeof maybeExpression.value !== "object" ||
maybeExpression.value.tag !== "RESyntaxError"
) {
throw new Error("Expected syntax error");
}
return { tag: "Error", value: maybeExpression.value };
}
}
// export function parse(
// squiggleString: string
// ): result<AnyPeggyNode, Extract<errorValue, { tag: "RESyntaxError" }>> {
// const maybeExpression = parseRescript(squiggleString);
// if (maybeExpression.tag === "Ok") {
// return { tag: "Ok", value: maybeExpression.value as AnyPeggyNode };
// } else {
// if (
// typeof maybeExpression.value !== "object" ||
// maybeExpression.value.tag !== "RESyntaxError"
// ) {
// throw new Error("Expected syntax error");
// }
// return { tag: "Error", value: maybeExpression.value };
// }
// }

View File

@ -1,21 +1,26 @@
export type result<a, b> =
| {
tag: "Ok";
value: a;
}
| {
tag: "Error";
value: b;
};
import { result } from "../rescript/ForTS/ForTS_Result_tag";
export { result };
export function resultMap<a, b, c>(
r: result<a, c>,
mapFn: (x: a) => b
): result<b, c> {
r: result<a, b>,
mapValue: (x: a) => c
): result<c, b> {
if (r.tag === "Ok") {
return { tag: "Ok", value: mapFn(r.value) };
return { tag: "Ok", value: mapValue(r.value) };
} else {
return r;
return { tag: "Error", value: r.value };
}
}
export function resultMap2<a, b, c, d>(
r: result<a, b>,
mapValue: (x: a) => c,
mapError: (y: b) => d
): result<c, d> {
if (r.tag === "Ok") {
return { tag: "Ok", value: mapValue(r.value) };
} else {
return { tag: "Error", value: mapError(r.value) };
}
}

View File

@ -1,5 +1,6 @@
// Genetic Distribution happens to be abstract distribution
@genType type distribution = DistributionTypes.genericDist
@genType type distributionError = DistributionTypes.error
@genType type pointSetDistribution = ForTS_Distribution_PointSetDistribution.pointSetDistribution
@genType type sampleSetDistribution = ForTS_Distribution_SampleSetDistribution.sampleSetDistribution
@genType type symbolicDistribution = ForTS_Distribution_SymbolicDistribution.symbolicDistribution
@ -73,3 +74,11 @@ let inv = DistributionOperation.Constructors.inv
let pdf = DistributionOperation.Constructors.pdf
@genType
let normalize = DistributionOperation.Constructors.normalize
@genType
let toPointSet = (variant: distribution, env: environment) =>
GenericDist.toPointSet(variant, ~sampleCount=env.sampleCount, ~xyPointLength=env.xyPointLength, ())
@genType
let toString = (variant: distribution) =>
GenericDist.toString(variant)

View File

@ -1,4 +1,7 @@
@genType type pointSetDistribution = PointSetTypes.pointSetDist
@genType type continuousShape = PointSetTypes.continuousShape
@genType type discreteShape = PointSetTypes.discreteShape
@genType type mixedShape = PointSetTypes.mixedShape
@module("ForTS_Distribution_PointSetDistribution_tag") @scope("pointSetDistributionTag")
external pstMixed_: int = "PstMixed"

View File

@ -11,9 +11,9 @@
"outDir": "./dist",
"declarationDir": "./dist",
"declaration": true,
"composite": true
},
"composite": true,
"target": "ES6",
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts", "webpack.config.js"]
}