Merge pull request #420 from quantified-uncertainty/dictionary-view

Add Dictionary Viewer and Recursive Array viewer
This commit is contained in:
Sam Nolan 2022-04-28 16:58:34 -04:00 committed by GitHub
commit b72e7b42c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 202 additions and 3 deletions

View File

@ -44,6 +44,8 @@ export const VariableBox: React.FC<{
);
};
let RecordKeyHeader = styled.h3``;
export interface SquiggleItemProps {
/** The input string for squiggle */
expression: squiggleExpression;
@ -104,6 +106,17 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
))}
</VariableBox>
);
case "record":
return (
<VariableBox heading="Record">
{Object.entries(expression.value).map(([key, r]) => (
<>
<RecordKeyHeader>{key}</RecordKeyHeader>
<SquiggleItem expression={r} width={width - 20} height={50} />
</>
))}
</VariableBox>
);
default:
return (
<ErrorBox heading="No Viewer">

View File

@ -42,6 +42,39 @@ describe("Log function", () => {
});
});
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("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.

View File

@ -10,6 +10,9 @@ import {
continuousShape,
discreteShape,
distributionErrorToString,
mixedShape,
sampleSetDist,
symbolicDist,
} from "../rescript/TypescriptInterface.gen";
export {
makeSampleSetDist,
@ -90,6 +93,7 @@ export type squiggleExpression =
| tagged<"distribution", Distribution>
| tagged<"number", number>
| tagged<"record", { [key: string]: squiggleExpression }>;
export function run(
squiggleString: string,
samplingInputs?: samplingParams
@ -107,9 +111,36 @@ function createTsExport(
): squiggleExpression {
switch (x.tag) {
case "EvArray":
// genType doesn't convert anything more than 2 layers down into {tag: x, value: x}
// format, leaving it as the raw values. This converts the raw values
// directly into typescript values.
//
// The casting here is because genType is about the types of the returned
// values, claiming they are fully recursive when that's not actually the
// case
return tag(
"array",
x.value.map((x) => createTsExport(x, sampEnv))
x.value.map((arrayItem): squiggleExpression => {
switch (arrayItem.tag) {
case "EvRecord":
return tag(
"record",
_.mapValues(arrayItem.value, (recordValue: unknown) =>
convertRawToTypescript(recordValue as rescriptExport, sampEnv)
)
);
case "EvArray":
let y = arrayItem.value as unknown as rescriptExport[];
return tag(
"array",
y.map((childArrayItem) =>
convertRawToTypescript(childArrayItem, sampEnv)
)
);
default:
return createTsExport(arrayItem, sampEnv);
}
})
);
case "EvBool":
return tag("boolean", x.value);
@ -120,10 +151,14 @@ function createTsExport(
case "EvNumber":
return tag("number", x.value);
case "EvRecord":
return tag(
// genType doesn't support records, so we have to do the raw conversion ourself
let result: tagged<"record", { [key: string]: squiggleExpression }> = tag(
"record",
_.mapValues(x.value, (x) => createTsExport(x, sampEnv))
_.mapValues(x.value, (x: unknown) =>
convertRawToTypescript(x as rescriptExport, sampEnv)
)
);
return result;
case "EvString":
return tag("string", x.value);
case "EvSymbol":
@ -131,6 +166,118 @@ function createTsExport(
}
}
// Helper functions to convert the recsript representations that genType doesn't
// cover
function convertRawToTypescript(
result: rescriptExport,
sampEnv: samplingParams
): squiggleExpression {
switch (result.TAG) {
case 0: // EvArray
return tag(
"array",
result._0.map((x) => convertRawToTypescript(x, sampEnv))
);
case 1: // EvBool
return tag("boolean", result._0);
case 2: // EvCall
return tag("call", result._0);
case 3: // EvDistribution
return tag(
"distribution",
new Distribution(
convertRawDistributionToGenericDist(result._0),
sampEnv
)
);
case 4: // EvNumber
return tag("number", result._0);
case 5: // EvRecord
return tag(
"record",
_.mapValues(result._0, (x) => convertRawToTypescript(x, sampEnv))
);
case 6: // EvString
return tag("string", result._0);
case 7: // EvSymbol
return tag("symbol", result._0);
}
}
function convertRawDistributionToGenericDist(
result: rescriptDist
): genericDist {
switch (result.TAG) {
case 0: // Point Set Dist
switch (result._0.TAG) {
case 0: // Mixed
return tag("PointSet", tag("Mixed", result._0._0));
case 1: // Discrete
return tag("PointSet", tag("Discrete", result._0._0));
case 2: // Continuous
return tag("PointSet", tag("Continuous", result._0._0));
}
case 1: // Sample Set Dist
return tag("SampleSet", result._0);
case 2: // Symbolic Dist
return tag("Symbolic", result._0);
}
}
// Raw rescript types.
type rescriptExport =
| {
TAG: 0; // EvArray
_0: rescriptExport[];
}
| {
TAG: 1; // EvBool
_0: boolean;
}
| {
TAG: 2; // EvCall
_0: string;
}
| {
TAG: 3; // EvDistribution
_0: rescriptDist;
}
| {
TAG: 4; // EvNumber
_0: number;
}
| {
TAG: 5; // EvRecord
_0: { [key: string]: rescriptExport };
}
| {
TAG: 6; // EvString
_0: string;
}
| {
TAG: 7; // EvSymbol
_0: string;
};
type rescriptDist =
| { TAG: 0; _0: rescriptPointSetDist }
| { TAG: 1; _0: sampleSetDist }
| { TAG: 2; _0: symbolicDist };
type rescriptPointSetDist =
| {
TAG: 0; // Mixed
_0: mixedShape;
}
| {
TAG: 1; // Discrete
_0: discreteShape;
}
| {
TAG: 2; // ContinuousShape
_0: continuousShape;
};
export function resultExn<a, c>(r: result<a, c>): a | c {
return r.value;
}

View File

@ -13,6 +13,12 @@ type samplingParams = DistributionOperation.env
@genType
type genericDist = DistributionTypes.genericDist
@genType
type sampleSetDist = SampleSetDist.t
@genType
type symbolicDist = SymbolicDistTypes.symbolicDist
@genType
type distributionError = DistributionTypes.error