Refactor parsing to lib files
This commit is contained in:
parent
a5a131daf1
commit
9cc000070b
|
@ -17,6 +17,8 @@ import {
|
||||||
DistributionChartSpecOptions,
|
DistributionChartSpecOptions,
|
||||||
} from "../lib/distributionSpecBuilder";
|
} from "../lib/distributionSpecBuilder";
|
||||||
import { NumberShower } from "./NumberShower";
|
import { NumberShower } from "./NumberShower";
|
||||||
|
import { Plot, parsePlot } from "../lib/plotting";
|
||||||
|
import { flattenResult, all } from "../lib/utility";
|
||||||
|
|
||||||
export type DistributionPlottingSettings = {
|
export type DistributionPlottingSettings = {
|
||||||
/** Whether to show a summary of means, stdev, percentiles etc */
|
/** Whether to show a summary of means, stdev, percentiles etc */
|
||||||
|
@ -25,12 +27,6 @@ export type DistributionPlottingSettings = {
|
||||||
showControls: boolean;
|
showControls: boolean;
|
||||||
} & DistributionChartSpecOptions;
|
} & DistributionChartSpecOptions;
|
||||||
|
|
||||||
export type LabeledDistribution = { name: string; distribution: Distribution };
|
|
||||||
|
|
||||||
export type Plot = {
|
|
||||||
distributions: LabeledDistribution[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type DistributionChartProps = {
|
export type DistributionChartProps = {
|
||||||
plot: Plot;
|
plot: Plot;
|
||||||
width?: number;
|
width?: number;
|
||||||
|
@ -42,99 +38,6 @@ export function defaultPlot(distribution: Distribution): Plot {
|
||||||
return { distributions: [{ name: "default", distribution }] };
|
return { distributions: [{ name: "default", distribution }] };
|
||||||
}
|
}
|
||||||
|
|
||||||
function error<a, b>(err: b): result<a, b> {
|
|
||||||
return { tag: "Error", value: err };
|
|
||||||
}
|
|
||||||
|
|
||||||
function ok<a, b>(x: a): result<a, b> {
|
|
||||||
return { tag: "Ok", value: x };
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseString(expr: squiggleExpression): result<string, string> {
|
|
||||||
if (expr.tag === "string") {
|
|
||||||
return ok(expr.value);
|
|
||||||
} else {
|
|
||||||
return error("Expression was not string");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseRecord(
|
|
||||||
expr: squiggleExpression
|
|
||||||
): result<{ [key: string]: squiggleExpression }, string> {
|
|
||||||
if (expr.tag === "record") {
|
|
||||||
return ok(expr.value);
|
|
||||||
} else {
|
|
||||||
return error("Expression was not a record");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseDistribution(
|
|
||||||
expr: squiggleExpression
|
|
||||||
): result<Distribution, string> {
|
|
||||||
if (expr.tag === "distribution") {
|
|
||||||
return ok(expr.value);
|
|
||||||
} else {
|
|
||||||
return error("Expression was not a distribution");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseArray(
|
|
||||||
expr: squiggleExpression
|
|
||||||
): result<squiggleExpression[], string> {
|
|
||||||
if (expr.tag === "array") {
|
|
||||||
return ok(expr.value);
|
|
||||||
} else {
|
|
||||||
return error("Expression was not a distribution");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseField<a>(
|
|
||||||
record: { [key: string]: squiggleExpression },
|
|
||||||
field: string,
|
|
||||||
parser: (expr: squiggleExpression) => result<a, string>
|
|
||||||
): result<a, string> {
|
|
||||||
if (record[field]) {
|
|
||||||
return parser(record[field]);
|
|
||||||
} else {
|
|
||||||
return error("record does not have field " + field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function resultBind<a, b, c>(
|
|
||||||
x: result<a, b>,
|
|
||||||
fn: (y: a) => result<c, b>
|
|
||||||
): result<c, b> {
|
|
||||||
if (x.tag === "Ok") {
|
|
||||||
return fn(x.value);
|
|
||||||
} else {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseLabeledDistribution(
|
|
||||||
x: squiggleExpression
|
|
||||||
): result<LabeledDistribution, string> {
|
|
||||||
return resultBind(parseRecord(x), (record) =>
|
|
||||||
resultBind(parseField(record, "name", parseString), (name) =>
|
|
||||||
resultBind(
|
|
||||||
parseField(record, "distribution", parseDistribution),
|
|
||||||
(distribution) => ok({ name, distribution })
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function parsePlot(record: {
|
|
||||||
[key: string]: squiggleExpression;
|
|
||||||
}): result<Plot, string> {
|
|
||||||
return resultBind(parseField(record, "distributions", parseArray), (array) =>
|
|
||||||
resultBind(
|
|
||||||
flattenResult(array.map(parseLabeledDistribution)),
|
|
||||||
(distributions) => ok({ distributions })
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function makePlot(record: {
|
export function makePlot(record: {
|
||||||
[key: string]: squiggleExpression;
|
[key: string]: squiggleExpression;
|
||||||
}): Plot | void {
|
}): Plot | void {
|
||||||
|
@ -143,26 +46,6 @@ export function makePlot(record: {
|
||||||
return plotResult.value;
|
return plotResult.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function all(arr: boolean[]): boolean {
|
|
||||||
return arr.reduce((x, y) => x && y, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function flattenResult<a, b>(x: result<a, b>[]): result<a[], b> {
|
|
||||||
if (x.length === 0) {
|
|
||||||
return { tag: "Ok", value: [] };
|
|
||||||
} else {
|
|
||||||
if (x[0].tag === "Error") {
|
|
||||||
return x[0];
|
|
||||||
} else {
|
|
||||||
let rest = flattenResult(x.splice(1));
|
|
||||||
if (rest.tag === "Error") {
|
|
||||||
return rest;
|
|
||||||
} else {
|
|
||||||
return { tag: "Ok", value: [x[0].value].concat(rest.value) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
|
|
90
packages/components/src/lib/plotting.ts
Normal file
90
packages/components/src/lib/plotting.ts
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
import { Distribution, result, squiggleExpression } from "@quri/squiggle-lang";
|
||||||
|
import { flattenResult, resultBind } from "./utility";
|
||||||
|
|
||||||
|
export type LabeledDistribution = { name: string; distribution: Distribution };
|
||||||
|
|
||||||
|
export type Plot = {
|
||||||
|
distributions: LabeledDistribution[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function error<a, b>(err: b): result<a, b> {
|
||||||
|
return { tag: "Error", value: err };
|
||||||
|
}
|
||||||
|
|
||||||
|
function ok<a, b>(x: a): result<a, b> {
|
||||||
|
return { tag: "Ok", value: x };
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseString(expr: squiggleExpression): result<string, string> {
|
||||||
|
if (expr.tag === "string") {
|
||||||
|
return ok(expr.value);
|
||||||
|
} else {
|
||||||
|
return error("Expression was not string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseRecord(
|
||||||
|
expr: squiggleExpression
|
||||||
|
): result<{ [key: string]: squiggleExpression }, string> {
|
||||||
|
if (expr.tag === "record") {
|
||||||
|
return ok(expr.value);
|
||||||
|
} else {
|
||||||
|
return error("Expression was not a record");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDistribution(
|
||||||
|
expr: squiggleExpression
|
||||||
|
): result<Distribution, string> {
|
||||||
|
if (expr.tag === "distribution") {
|
||||||
|
return ok(expr.value);
|
||||||
|
} else {
|
||||||
|
return error("Expression was not a distribution");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseArray(
|
||||||
|
expr: squiggleExpression
|
||||||
|
): result<squiggleExpression[], string> {
|
||||||
|
if (expr.tag === "array") {
|
||||||
|
return ok(expr.value);
|
||||||
|
} else {
|
||||||
|
return error("Expression was not a distribution");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseField<a>(
|
||||||
|
record: { [key: string]: squiggleExpression },
|
||||||
|
field: string,
|
||||||
|
parser: (expr: squiggleExpression) => result<a, string>
|
||||||
|
): result<a, string> {
|
||||||
|
if (record[field]) {
|
||||||
|
return parser(record[field]);
|
||||||
|
} else {
|
||||||
|
return error("record does not have field " + field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseLabeledDistribution(
|
||||||
|
x: squiggleExpression
|
||||||
|
): result<LabeledDistribution, string> {
|
||||||
|
return resultBind(parseRecord(x), (record) =>
|
||||||
|
resultBind(parseField(record, "name", parseString), (name) =>
|
||||||
|
resultBind(
|
||||||
|
parseField(record, "distribution", parseDistribution),
|
||||||
|
(distribution) => ok({ name, distribution })
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parsePlot(record: {
|
||||||
|
[key: string]: squiggleExpression;
|
||||||
|
}): result<Plot, string> {
|
||||||
|
return resultBind(parseField(record, "distributions", parseArray), (array) =>
|
||||||
|
resultBind(
|
||||||
|
flattenResult(array.map(parseLabeledDistribution)),
|
||||||
|
(distributions) => ok({ distributions })
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
33
packages/components/src/lib/utility.ts
Normal file
33
packages/components/src/lib/utility.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import { result } from "@quri/squiggle-lang";
|
||||||
|
|
||||||
|
export function flattenResult<a, b>(x: result<a, b>[]): result<a[], b> {
|
||||||
|
if (x.length === 0) {
|
||||||
|
return { tag: "Ok", value: [] };
|
||||||
|
} else {
|
||||||
|
if (x[0].tag === "Error") {
|
||||||
|
return x[0];
|
||||||
|
} else {
|
||||||
|
let rest = flattenResult(x.splice(1));
|
||||||
|
if (rest.tag === "Error") {
|
||||||
|
return rest;
|
||||||
|
} else {
|
||||||
|
return { tag: "Ok", value: [x[0].value].concat(rest.value) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resultBind<a, b, c>(
|
||||||
|
x: result<a, b>,
|
||||||
|
fn: (y: a) => result<c, b>
|
||||||
|
): result<c, b> {
|
||||||
|
if (x.tag === "Ok") {
|
||||||
|
return fn(x.value);
|
||||||
|
} else {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function all(arr: boolean[]): boolean {
|
||||||
|
return arr.reduce((x, y) => x && y, true);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user