diff --git a/packages/components/src/components/DistributionChart.tsx b/packages/components/src/components/DistributionChart.tsx
index f1253629..b8310609 100644
--- a/packages/components/src/components/DistributionChart.tsx
+++ b/packages/components/src/components/DistributionChart.tsx
@@ -42,27 +42,105 @@ export function defaultPlot(distribution: Distribution): Plot {
return { distributions: [{ name: "default", distribution }] };
}
-export function makePlot(expression: {
+function error(err: b): result {
+ return { tag: "Error", value: err };
+}
+
+function ok(x: a): result {
+ return { tag: "Ok", value: x };
+}
+
+function parseString(expr: squiggleExpression): result {
+ 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 {
+ if (expr.tag === "distribution") {
+ return ok(expr.value);
+ } else {
+ return error("Expression was not a distribution");
+ }
+}
+
+function parseArray(
+ expr: squiggleExpression
+): result {
+ if (expr.tag === "array") {
+ return ok(expr.value);
+ } else {
+ return error("Expression was not a distribution");
+ }
+}
+
+function parseField(
+ record: { [key: string]: squiggleExpression },
+ field: string,
+ parser: (expr: squiggleExpression) => result
+): result {
+ if (record[field]) {
+ return parser(record[field]);
+ } else {
+ return error("record does not have field " + field);
+ }
+}
+
+function resultBind(
+ x: result,
+ fn: (y: a) => result
+): result {
+ if (x.tag === "Ok") {
+ return fn(x.value);
+ } else {
+ return x;
+ }
+}
+
+function parseLabeledDistribution(
+ x: squiggleExpression
+): result {
+ 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 {
+ return resultBind(parseField(record, "distributions", parseArray), (array) =>
+ resultBind(
+ flattenResult(array.map(parseLabeledDistribution)),
+ (distributions) => ok({ distributions })
+ )
+ );
+}
+
+export function makePlot(record: {
[key: string]: squiggleExpression;
}): Plot | void {
- if (expression["distributions"].tag === "array") {
- let distributions: LabeledDistribution[] = expression["distributions"].value
- .map((x) => {
- if (
- x.tag === "record" &&
- x.value["name"] &&
- x.value["name"].tag === "string" &&
- x.value["distribution"] &&
- x.value["distribution"].tag === "distribution"
- ) {
- return {
- name: x.value["name"].value,
- distribution: x.value["distribution"].value,
- };
- }
- })
- .filter((x): x is LabeledDistribution => x !== undefined);
- return { distributions };
+ const plotResult = parsePlot(record);
+ if (plotResult.tag == "Ok") {
+ return plotResult.value;
}
}
function all(arr: boolean[]): boolean {