Merge pull request #420 from quantified-uncertainty/dictionary-view
Add Dictionary Viewer and Recursive Array viewer
This commit is contained in:
commit
b72e7b42c4
|
@ -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">
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user