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 {