reimplement parsePlot with yup

This commit is contained in:
Vyacheslav Matyukhin 2022-08-19 15:17:31 +04:00
parent 61051ffe5f
commit 7866203ac4
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C

View File

@ -1,5 +1,5 @@
import * as yup from "yup";
import { Distribution, result, squiggleExpression } from "@quri/squiggle-lang";
import { flattenResult, resultBind } from "./utility";
export type LabeledDistribution = { name: string; distribution: Distribution };
@ -15,76 +15,47 @@ 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 })
const schema = yup
.object()
.strict()
.noUnknown()
.shape({
distributions: yup.object().shape({
tag: yup.mixed().oneOf(["array"]),
value: yup
.array()
.of(
yup.object().shape({
tag: yup.mixed().oneOf(["record"]),
value: yup.object().shape({
name: yup.object().shape({
tag: yup.mixed().oneOf(["string"]),
value: yup.string().required(),
}),
distribution: yup.object().shape({
tag: yup.mixed().oneOf(["distribution"]),
value: yup.mixed(),
}),
}),
})
)
)
);
}
.required(),
}),
});
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 })
)
);
try {
const plotRecord = schema.validateSync(record);
return ok({
distributions: plotRecord.distributions.value.map((x) => ({
name: x.value.name.value,
distribution: x.value.distribution.value,
})),
});
} catch (e) {
const message = e instanceof Error ? e.message : "Unknown error";
return error(message);
}
}