Merge branch 'develop' into collapsible

This commit is contained in:
Vyacheslav Matyukhin 2022-07-22 23:59:50 +04:00
commit 43fed64f82
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
42 changed files with 1148 additions and 457 deletions

View File

@ -0,0 +1,287 @@
import * as React from "react";
import {
squiggleExpression,
environment,
declaration,
} from "@quri/squiggle-lang";
import { NumberShower } from "./NumberShower";
import {
DistributionChart,
DistributionPlottingSettings,
} from "./DistributionChart";
import { FunctionChart, FunctionChartSettings } from "./FunctionChart";
function getRange<a>(x: declaration<a>) {
const first = x.args[0];
switch (first.tag) {
case "Float": {
return { floats: { min: first.value.min, max: first.value.max } };
}
case "Date": {
return { time: { min: first.value.min, max: first.value.max } };
}
}
}
function getChartSettings<a>(x: declaration<a>): FunctionChartSettings {
const range = getRange(x);
const min = range.floats ? range.floats.min : 0;
const max = range.floats ? range.floats.max : 10;
return {
start: min,
stop: max,
count: 20,
};
}
interface VariableBoxProps {
heading: string;
children: React.ReactNode;
showTypes: boolean;
}
export const VariableBox: React.FC<VariableBoxProps> = ({
heading = "Error",
children,
showTypes = false,
}) => {
if (showTypes) {
return (
<div className="bg-white border border-grey-200 m-2">
<div className="border-b border-grey-200 p-3">
<header className="font-mono">{heading}</header>
</div>
<div className="p-3">{children}</div>
</div>
);
} else {
return <div>{children}</div>;
}
};
export interface SquiggleItemProps {
/** The input string for squiggle */
expression: squiggleExpression;
width?: number;
height: number;
distributionPlotSettings: DistributionPlottingSettings;
/** Whether to show type information */
showTypes: boolean;
/** Settings for displaying functions */
chartSettings: FunctionChartSettings;
/** Environment for further function executions */
environment: environment;
}
export const SquiggleItem: React.FC<SquiggleItemProps> = ({
expression,
width,
height,
distributionPlotSettings,
showTypes = false,
chartSettings,
environment,
}) => {
switch (expression.tag) {
case "number":
return (
<VariableBox heading="Number" showTypes={showTypes}>
<div className="font-semibold text-slate-600">
<NumberShower precision={3} number={expression.value} />
</div>
</VariableBox>
);
case "distribution": {
const distType = expression.value.type();
return (
<VariableBox
heading={`Distribution (${distType})`}
showTypes={showTypes}
>
{distType === "Symbolic" && showTypes ? (
<div>{expression.value.toString()}</div>
) : null}
<DistributionChart
distribution={expression.value}
{...distributionPlotSettings}
height={height}
width={width}
/>
</VariableBox>
);
}
case "string":
return (
<VariableBox heading="String" showTypes={showTypes}>
<span className="text-slate-400">"</span>
<span className="text-slate-600 font-semibold">
{expression.value}
</span>
<span className="text-slate-400">"</span>
</VariableBox>
);
case "boolean":
return (
<VariableBox heading="Boolean" showTypes={showTypes}>
{expression.value.toString()}
</VariableBox>
);
case "symbol":
return (
<VariableBox heading="Symbol" showTypes={showTypes}>
<span className="text-slate-500 mr-2">Undefined Symbol:</span>
<span className="text-slate-600">{expression.value}</span>
</VariableBox>
);
case "call":
return (
<VariableBox heading="Call" showTypes={showTypes}>
{expression.value}
</VariableBox>
);
case "array":
return (
<VariableBox heading="Array" showTypes={showTypes}>
{expression.value.map((r, i) => (
<div key={i} className="flex pt-1">
<div className="flex-none bg-slate-100 rounded-sm px-1">
<header className="text-slate-400 font-mono">{i}</header>
</div>
<div className="px-2 mb-2 grow">
<SquiggleItem
key={i}
expression={r}
width={width !== undefined ? width - 20 : width}
height={50}
distributionPlotSettings={distributionPlotSettings}
showTypes={showTypes}
chartSettings={chartSettings}
environment={environment}
/>
</div>
</div>
))}
</VariableBox>
);
case "record":
return (
<VariableBox heading="Record" showTypes={showTypes}>
<div className="space-y-3">
{Object.entries(expression.value).map(([key, r]) => (
<div key={key} className="flex space-x-2">
<div className="flex-none">
<header className="text-slate-500 font-mono">{key}:</header>
</div>
<div className="px-2 grow bg-gray-50 border border-gray-100 rounded-sm">
<SquiggleItem
expression={r}
width={width !== undefined ? width - 20 : width}
height={height / 3}
showTypes={showTypes}
distributionPlotSettings={distributionPlotSettings}
chartSettings={chartSettings}
environment={environment}
/>
</div>
</div>
))}
</div>
</VariableBox>
);
case "arraystring":
return (
<VariableBox heading="Array String" showTypes={showTypes}>
{expression.value.map((r) => `"${r}"`).join(", ")}
</VariableBox>
);
case "date":
return (
<VariableBox heading="Date" showTypes={showTypes}>
{expression.value.toDateString()}
</VariableBox>
);
case "void":
return (
<VariableBox heading="Void" showTypes={showTypes}>
{"Void"}
</VariableBox>
);
case "timeDuration": {
return (
<VariableBox heading="Time Duration" showTypes={showTypes}>
<NumberShower precision={3} number={expression.value} />
</VariableBox>
);
}
case "lambda":
return (
<VariableBox heading="Function" showTypes={showTypes}>
<div className="text-amber-700 bg-amber-100 rounded-md font-mono p-1 pl-2 mb-3 mt-1 text-sm">{`function(${expression.value.parameters.join(
","
)})`}</div>
<FunctionChart
fn={expression.value}
chartSettings={chartSettings}
distributionPlotSettings={distributionPlotSettings}
height={height}
environment={{
sampleCount: environment.sampleCount / 10,
xyPointLength: environment.xyPointLength / 10,
}}
/>
</VariableBox>
);
case "lambdaDeclaration": {
return (
<VariableBox heading="Function Declaration" showTypes={showTypes}>
<FunctionChart
fn={expression.value.fn}
chartSettings={getChartSettings(expression.value)}
distributionPlotSettings={distributionPlotSettings}
height={height}
environment={{
sampleCount: environment.sampleCount / 10,
xyPointLength: environment.xyPointLength / 10,
}}
/>
</VariableBox>
);
}
case "module": {
return (
<VariableBox heading="Module" showTypes={showTypes}>
<div className="space-y-3">
{Object.entries(expression.value)
.filter(([key, r]) => key !== "Math")
.map(([key, r]) => (
<div key={key} className="flex space-x-2">
<div className="flex-none">
<header className="text-slate-500 font-mono">{key}:</header>
</div>
<div className="px-2 grow bg-gray-50 border border-gray-100 rounded-sm">
<SquiggleItem
expression={r}
width={width !== undefined ? width - 20 : width}
height={height / 3}
showTypes={showTypes}
distributionPlotSettings={distributionPlotSettings}
chartSettings={chartSettings}
environment={environment}
/>
</div>
</div>
))}
</div>
</VariableBox>
);
}
default: {
return (
<div>
<span>No display for type: </span>{" "}
<span className="font-semibold text-slate-600">{expression.tag}</span>
</div>
);
}
}
};

View File

@ -154,6 +154,12 @@ export const ExpressionViewer: React.FC<Props> = ({
{() => expression.value.toDateString()}
</VariableBox>
);
case "void":
return (
<VariableBox path={path} heading="Void">
{() => "Void"}
</VariableBox>
);
case "timeDuration": {
return (
<VariableBox path={path} heading="Time Duration">

View File

@ -17,14 +17,6 @@ describe("builtin", () => {
testEval("1-1", "Ok(0)")
testEval("2>1", "Ok(true)")
testEval("concat('a','b')", "Ok('ab')")
testEval(
"addOne(t)=t+1; toList(mapSamples(fromSamples([1,2,3,4,5,6]), addOne))",
"Ok([2,3,4,5,6,7])",
)
testEval(
"toList(mapSamplesN([fromSamples([1,2,3,4,5,6]), fromSamples([6, 5, 4, 3, 2, 1])], {|x| x[0] > x[1] ? x[0] : x[1]}))",
"Ok([6,5,4,4,5,6])",
)
})
describe("builtin exception", () => {

View File

@ -0,0 +1,20 @@
open Jest
open Reducer_Peggy_TestHelpers
describe("Peggy void", () => {
//literal
testToExpression("()", "{()}", ~v="()", ())
testToExpression(
"fn()=1",
"{(:$_let_$ :fn (:$$_lambda_$$ [_] {1}))}",
~v="@{fn: lambda(_=>internal code)}",
(),
)
testToExpression("fn()=1; fn()", "{(:$_let_$ :fn (:$$_lambda_$$ [_] {1})); (:fn ())}", ~v="1", ())
testToExpression(
"fn(a)=(); call fn(1)",
"{(:$_let_$ :fn (:$$_lambda_$$ [a] {()})); (:$_let_$ :_ {(:fn 1)})}",
~v="@{_: (),fn: lambda(a=>internal code)}",
(),
)
})

View File

@ -1,15 +1,6 @@
open Jest
open Reducer_TestHelpers
describe("map reduce", () => {
testEvalToBe("double(x)=2*x; arr=[1,2,3]; map(arr, double)", "Ok([2,4,6])")
testEvalToBe("myadd(acc,x)=acc+x; arr=[1,2,3]; reduce(arr, 0, myadd)", "Ok(6)")
testEvalToBe("change(acc,x)=acc*x+x; arr=[1,2,3]; reduce(arr, 0, change)", "Ok(15)")
testEvalToBe("change(acc,x)=acc*x+x; arr=[1,2,3]; reduceReverse(arr, 0, change)", "Ok(9)")
testEvalToBe("arr=[1,2,3]; reverse(arr)", "Ok([3,2,1])")
testEvalToBe("check(x)=(x==2);arr=[1,2,3]; filter(arr,check)", "Ok([2])")
})
Skip.describe("map reduce (sam)", () => {
testEvalToBe("addone(x)=x+1; map(2, addone)", "Error???")
testEvalToBe("addone(x)=x+1; map(2, {x: addone})", "Error???")

View File

@ -41,12 +41,6 @@ describe("eval on distribution functions", () => {
describe("normalize", () => {
testEval("normalize(normal(5,2))", "Ok(Normal(5,2))")
})
describe("toPointSet", () => {
testEval("toPointSet(normal(5,2))", "Ok(Point Set Distribution)")
})
describe("toSampleSet", () => {
testEval("toSampleSet(normal(5,2), 100)", "Ok(Sample Set Distribution)")
})
describe("add", () => {
testEval("add(normal(5,2), normal(10,2))", "Ok(Normal(15,2.8284271247461903))")
testEval("add(normal(5,2), lognormal(10,2))", "Ok(Sample Set Distribution)")

View File

@ -16,6 +16,13 @@ describe("FunctionRegistry Library", () => {
testEvalToBe("List.first([3,5,8])", "Ok(3)")
testEvalToBe("List.last([3,5,8])", "Ok(8)")
testEvalToBe("List.reverse([3,5,8])", "Ok([8,5,3])")
testEvalToBe("double(x)=2*x; arr=[1,2,3]; List.map(arr, double)", "Ok([2,4,6])")
testEvalToBe("double(x)=2*x; arr=[1,2,3]; map(arr, double)", "Ok([2,4,6])")
testEvalToBe("myadd(acc,x)=acc+x; arr=[1,2,3]; List.reduce(arr, 0, myadd)", "Ok(6)")
testEvalToBe("change(acc,x)=acc*x+x; arr=[1,2,3]; List.reduce(arr, 0, change)", "Ok(15)")
testEvalToBe("change(acc,x)=acc*x+x; arr=[1,2,3]; List.reduceReverse(arr, 0, change)", "Ok(9)")
testEvalToBe("check(x)=(x==2);arr=[1,2,3]; List.filter(arr,check)", "Ok([2])")
testEvalToBe("arr=[1,2,3]; List.reverse(arr)", "Ok([3,2,1])")
testEvalToBe("Dist.normal(5,2)", "Ok(Normal(5,2))")
testEvalToBe("normal(5,2)", "Ok(Normal(5,2))")
testEvalToBe("normal({mean:5,stdev:2})", "Ok(Normal(5,2))")
@ -53,6 +60,17 @@ describe("FunctionRegistry Library", () => {
)
testEvalToBe("Dist.logScore({estimate: normal(5,2), answer: 4.5})", "Ok(1.6433360626394853)")
testEvalToBe("Dist.klDivergence(normal(5,2), normal(5,1.5))", "Ok(0.06874342818671068)")
testEvalToBe("SampleSet.fromList([3,5,2,3,5,2,3,5,2,3,3,5])", "Ok(Sample Set Distribution)")
testEvalToBe("SampleSet.fromList([3,5,2,3,5,2,3,5,2,3,3,5])", "Ok(Sample Set Distribution)")
testEvalToBe("SampleSet.fromFn({|| sample(normal(5,2))})", "Ok(Sample Set Distribution)")
testEvalToBe(
"addOne(t)=t+1; SampleSet.toList(SampleSet.map(SampleSet.fromList([1,2,3,4,5,6]), addOne))",
"Ok([2,3,4,5,6,7])",
)
testEvalToBe(
"SampleSet.toList(SampleSet.mapN([SampleSet.fromList([1,2,3,4,5,6]), SampleSet.fromList([6, 5, 4, 3, 2, 1])], {|x| x[0] > x[1] ? x[0] : x[1]}))",
"Ok([6,5,4,4,5,6])",
)
})
describe("Fn auto-testing", () => {

View File

@ -20,6 +20,7 @@
"test:ts": "jest __tests__/TS/",
"test:rescript": "jest --modulePathIgnorePatterns=__tests__/TS/*",
"test:watch": "jest --watchAll",
"test:fnRegistry": "jest __tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.bs.js",
"coverage:rescript": "rm -f *.coverage && yarn clean && BISECT_ENABLE=yes yarn build && yarn test:rescript && bisect-ppx-report html",
"coverage:ts": "yarn clean && yarn build && nyc --reporter=lcov yarn test:ts",
"coverage:rescript:ci": "yarn clean && BISECT_ENABLE=yes yarn build:rescript && yarn test:rescript && bisect-ppx-report send-to Codecov",
@ -31,6 +32,7 @@
"format:prettier": "prettier --write .",
"format": "yarn format:rescript && yarn format:prettier",
"prepack": "yarn build && yarn test && yarn bundle",
"all:rescript": "yarn build:rescript && yarn test:rescript && yarn format:rescript",
"all": "yarn build && yarn bundle && yarn test"
},
"keywords": [

View File

@ -120,77 +120,86 @@ function createTsExport(
x: expressionValue,
environment: environment
): 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(
(arrayItem): squiggleExpression =>
convertRawToTypescript(
arrayItem as unknown as rescriptExport,
environment
switch (x) {
case "EvVoid":
return tag("void", "");
default: {
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(
(arrayItem): squiggleExpression =>
convertRawToTypescript(
arrayItem as unknown as rescriptExport,
environment
)
)
)
);
case "EvArrayString":
return tag("arraystring", x.value);
case "EvBool":
return tag("boolean", x.value);
case "EvCall":
return tag("call", x.value);
case "EvLambda":
return tag("lambda", x.value);
case "EvDistribution":
return tag("distribution", new Distribution(x.value, environment));
case "EvNumber":
return tag("number", x.value);
case "EvRecord":
// 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: unknown) =>
convertRawToTypescript(x as rescriptExport, environment)
)
);
return result;
case "EvString":
return tag("string", x.value);
case "EvSymbol":
return tag("symbol", x.value);
case "EvDate":
return tag("date", x.value);
case "EvTimeDuration":
return tag("timeDuration", x.value);
case "EvDeclaration":
return tag("lambdaDeclaration", x.value);
case "EvTypeIdentifier":
return tag("typeIdentifier", x.value);
case "EvType":
let typeResult: tagged<"type", { [key: string]: squiggleExpression }> =
tag(
"type",
_.mapValues(x.value, (x: unknown) =>
convertRawToTypescript(x as rescriptExport, environment)
)
);
return typeResult;
case "EvModule":
let moduleResult: tagged<
"module",
{ [key: string]: squiggleExpression }
> = tag(
"module",
_.mapValues(x.value, (x: unknown) =>
convertRawToTypescript(x as rescriptExport, environment)
)
);
return moduleResult;
);
case "EvArrayString":
return tag("arraystring", x.value);
case "EvBool":
return tag("boolean", x.value);
case "EvCall":
return tag("call", x.value);
case "EvLambda":
return tag("lambda", x.value);
case "EvDistribution":
return tag("distribution", new Distribution(x.value, environment));
case "EvNumber":
return tag("number", x.value);
case "EvRecord":
// 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: unknown) =>
convertRawToTypescript(x as rescriptExport, environment)
)
);
return result;
case "EvString":
return tag("string", x.value);
case "EvSymbol":
return tag("symbol", x.value);
case "EvDate":
return tag("date", x.value);
case "EvTimeDuration":
return tag("timeDuration", x.value);
case "EvDeclaration":
return tag("lambdaDeclaration", x.value);
case "EvTypeIdentifier":
return tag("typeIdentifier", x.value);
case "EvType":
let typeResult: tagged<
"type",
{ [key: string]: squiggleExpression }
> = tag(
"type",
_.mapValues(x.value, (x: unknown) =>
convertRawToTypescript(x as rescriptExport, environment)
)
);
return typeResult;
case "EvModule":
let moduleResult: tagged<
"module",
{ [key: string]: squiggleExpression }
> = tag(
"module",
_.mapValues(x.value, (x: unknown) =>
convertRawToTypescript(x as rescriptExport, environment)
)
);
return moduleResult;
}
}
}
}

View File

@ -131,7 +131,8 @@ export type squiggleExpression =
| tagged<"record", { [key: string]: squiggleExpression }>
| tagged<"type", { [key: string]: squiggleExpression }>
| tagged<"typeIdentifier", string>
| tagged<"module", { [key: string]: squiggleExpression }>;
| tagged<"module", { [key: string]: squiggleExpression }>
| tagged<"void", string>;
export { lambdaValue };

View File

@ -47,6 +47,7 @@ type fnDefinition = {
array<internalExpressionValue>,
array<frValue>,
GenericDist.env,
Reducer_Expression_T.reducerFn,
) => result<internalExpressionValue, string>,
}
@ -184,6 +185,9 @@ module FRType = {
This module, Matcher, is fairly lengthy. However, only two functions from it
are meant to be used outside of it. These are findMatches and matchToDef in Matches.Registry.
The rest of it is just called from those two functions.
Update: This really should be completely re-done sometime, and tested. It works, but it's pretty messy. I'm sure
there are internal bugs, but the end functionality works, so I'm not too worried.
*/
module Matcher = {
module MatchSimple = {
@ -239,53 +243,82 @@ module Matcher = {
type definitionId = int
type match = Match.t<array<definitionId>, definitionId>
let match = (f: function, fnName: string, args: array<internalExpressionValue>): match => {
let matchedDefinition = () =>
E.A.getIndexBy(f.definitions, r =>
MatchSimple.isFullMatch(FnDefinition.match(r, fnName, args))
) |> E.O.fmap(r => Match.FullMatch(r))
let getMatchedNameOnlyDefinition = () => {
let nameMatchIndexes =
f.definitions
->E.A2.fmapi((index, r) =>
MatchSimple.isNameMatchOnly(FnDefinition.match(r, fnName, args)) ? Some(index) : None
let match = (
f: function,
nameSpace: option<string>,
fnName: string,
args: array<internalExpressionValue>,
): match => {
switch nameSpace {
| Some(ns) if ns !== f.nameSpace => Match.DifferentName
| _ => {
let matchedDefinition = () =>
E.A.getIndexBy(f.definitions, r =>
MatchSimple.isFullMatch(FnDefinition.match(r, fnName, args))
) |> E.O.fmap(r => Match.FullMatch(r))
let getMatchedNameOnlyDefinition = () => {
let nameMatchIndexes =
f.definitions
->E.A2.fmapi((index, r) =>
MatchSimple.isNameMatchOnly(FnDefinition.match(r, fnName, args))
? Some(index)
: None
)
->E.A.O.concatSomes
switch nameMatchIndexes {
| [] => None
| elements => Some(Match.SameNameDifferentArguments(elements))
}
}
E.A.O.firstSomeFnWithDefault(
[matchedDefinition, getMatchedNameOnlyDefinition],
Match.DifferentName,
)
->E.A.O.concatSomes
switch nameMatchIndexes {
| [] => None
| elements => Some(Match.SameNameDifferentArguments(elements))
}
}
E.A.O.firstSomeFnWithDefault(
[matchedDefinition, getMatchedNameOnlyDefinition],
Match.DifferentName,
)
}
}
module RegistryMatch = {
type match = {
nameSpace: string,
fnName: string,
inputIndex: int,
}
let makeMatch = (fnName: string, inputIndex: int) => {fnName: fnName, inputIndex: inputIndex}
let makeMatch = (nameSpace: string, fnName: string, inputIndex: int) => {
nameSpace: nameSpace,
fnName: fnName,
inputIndex: inputIndex,
}
}
module Registry = {
let _findExactMatches = (r: registry, fnName: string, args: array<internalExpressionValue>) => {
let functionMatchPairs = r.functions->E.A2.fmap(l => (l, Function.match(l, fnName, args)))
let _findExactMatches = (
r: registry,
nameSpace: option<string>,
fnName: string,
args: array<internalExpressionValue>,
) => {
let functionMatchPairs =
r.functions->E.A2.fmap(l => (l, Function.match(l, nameSpace, fnName, args)))
let fullMatch = functionMatchPairs->E.A.getBy(((_, match)) => Match.isFullMatch(match))
fullMatch->E.O.bind(((fn, match)) =>
switch match {
| FullMatch(index) => Some(RegistryMatch.makeMatch(fn.name, index))
| FullMatch(index) => Some(RegistryMatch.makeMatch(fn.nameSpace, fn.name, index))
| _ => None
}
)
}
let _findNameMatches = (r: registry, fnName: string, args: array<internalExpressionValue>) => {
let functionMatchPairs = r.functions->E.A2.fmap(l => (l, Function.match(l, fnName, args)))
let _findNameMatches = (
r: registry,
nameSpace: option<string>,
fnName: string,
args: array<internalExpressionValue>,
) => {
let functionMatchPairs =
r.functions->E.A2.fmap(l => (l, Function.match(l, nameSpace, fnName, args)))
let getNameMatches =
functionMatchPairs
->E.A2.fmap(((fn, match)) => Match.isNameMatchOnly(match) ? Some((fn, match)) : None)
@ -295,7 +328,7 @@ module Matcher = {
->E.A2.fmap(((fn, match)) =>
switch match {
| SameNameDifferentArguments(indexes) =>
indexes->E.A2.fmap(index => RegistryMatch.makeMatch(fn.name, index))
indexes->E.A2.fmap(index => RegistryMatch.makeMatch(fn.nameSpace, fn.name, index))
| _ => []
}
)
@ -306,22 +339,26 @@ module Matcher = {
let findMatches = (r: registry, fnName: string, args: array<internalExpressionValue>) => {
let fnNameInParts = Js.String.split(".", fnName)
let fnToSearch = E.A.get(fnNameInParts, 1) |> E.O.default(fnNameInParts[0])
let nameSpace = E.A.length(fnNameInParts) > 1 ? Some(fnNameInParts[0]) : None
switch _findExactMatches(r, fnToSearch, args) {
switch _findExactMatches(r, nameSpace, fnToSearch, args) {
| Some(r) => Match.FullMatch(r)
| None =>
switch _findNameMatches(r, fnToSearch, args) {
switch _findNameMatches(r, nameSpace, fnToSearch, args) {
| Some(r) => Match.SameNameDifferentArguments(r)
| None => Match.DifferentName
}
}
}
let matchToDef = (registry: registry, {fnName, inputIndex}: RegistryMatch.match): option<
fnDefinition,
> =>
let matchToDef = (
registry: registry,
{nameSpace, fnName, inputIndex}: RegistryMatch.match,
): option<fnDefinition> =>
registry.functions
->E.A.getBy(fn => fn.name === fnName)
->E.A.getBy(fn => {
nameSpace === fn.nameSpace && fnName === fn.name
})
->E.O.bind(fn => E.A.get(fn.definitions, inputIndex))
}
}
@ -342,10 +379,15 @@ module FnDefinition = {
}
}
let run = (t: t, args: array<internalExpressionValue>, env: GenericDist.env) => {
let run = (
t: t,
args: array<internalExpressionValue>,
env: GenericDist.env,
reducer: Reducer_Expression_T.reducerFn,
) => {
let argValues = FRType.matchWithExpressionValueArray(t.inputs, args)
switch argValues {
| Some(values) => t.run(args, values, env)
| Some(values) => t.run(args, values, env, reducer)
| None => Error("Incorrect Types")
}
}
@ -452,6 +494,7 @@ module Registry = {
~fnName: string,
~args: array<internalExpressionValue>,
~env: GenericDist.env,
~reducer: Reducer_Expression_T.reducerFn,
) => {
let relevantFunctions = Js.Dict.get(registry.fnNameDict, fnName) |> E.O.default([])
let modified = {functions: relevantFunctions, fnNameDict: registry.fnNameDict}
@ -468,7 +511,8 @@ module Registry = {
}
switch Matcher.Registry.findMatches(modified, fnName, args) {
| Matcher.Match.FullMatch(match) => match->matchToDef->E.O2.fmap(FnDefinition.run(_, args, env))
| Matcher.Match.FullMatch(match) =>
match->matchToDef->E.O2.fmap(FnDefinition.run(_, args, env, reducer))
| SameNameDifferentArguments(m) => Some(Error(showNameMatchDefinitions(m)))
| _ => None
}
@ -478,8 +522,9 @@ module Registry = {
registry,
(fnName, args): ReducerInterface_InternalExpressionValue.functionCall,
env,
reducer: Reducer_Expression_T.reducerFn,
) => {
_matchAndRun(~registry, ~fnName, ~args, ~env)->E.O2.fmap(
_matchAndRun(~registry, ~fnName, ~args, ~env, ~reducer)->E.O2.fmap(
E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)),
)
}

View File

@ -4,6 +4,8 @@ let impossibleError = "Wrong inputs / Logically impossible"
module Wrappers = {
let symbolic = r => DistributionTypes.Symbolic(r)
let pointSet = r => DistributionTypes.PointSet(r)
let sampleSet = r => DistributionTypes.SampleSet(r)
let evDistribution = r => ReducerInterface_InternalExpressionValue.IEvDistribution(r)
let evNumber = r => ReducerInterface_InternalExpressionValue.IEvNumber(r)
let evArray = r => ReducerInterface_InternalExpressionValue.IEvArray(r)

View File

@ -2,6 +2,7 @@ let fnList = Belt.Array.concatMany([
FR_Dict.library,
FR_Dist.library,
FR_Fn.library,
FR_Sampleset.library,
FR_List.library,
FR_Number.library,
FR_Pointset.library,

View File

@ -52,7 +52,7 @@ let library = [
FnDefinition.make(
~name="merge",
~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)],
~run=(inputs, _, _) => {
~run=(inputs, _, _, _) => {
switch inputs {
| [IEvRecord(d1), IEvRecord(d2)] => Internals.merge(d1, d2)->Ok
| _ => Error(impossibleError)
@ -74,7 +74,7 @@ let library = [
FnDefinition.make(
~name="mergeMany",
~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))],
~run=(_, inputs, _) =>
~run=(_, inputs, _, _) =>
inputs
->Prepare.ToTypedArray.dicts
->E.R2.fmap(E.Dict.concatMany)
@ -96,7 +96,7 @@ let library = [
FnDefinition.make(
~name="keys",
~inputs=[FRTypeDict(FRTypeAny)],
~run=(inputs, _, _) =>
~run=(inputs, _, _, _) =>
switch inputs {
| [IEvRecord(d1)] => Internals.keys(d1)->Ok
| _ => Error(impossibleError)
@ -116,7 +116,7 @@ let library = [
FnDefinition.make(
~name="values",
~inputs=[FRTypeDict(FRTypeAny)],
~run=(inputs, _, _) =>
~run=(inputs, _, _, _) =>
switch inputs {
| [IEvRecord(d1)] => Internals.values(d1)->Ok
| _ => Error(impossibleError)
@ -136,7 +136,7 @@ let library = [
FnDefinition.make(
~name="toList",
~inputs=[FRTypeDict(FRTypeAny)],
~run=(inputs, _, _) =>
~run=(inputs, _, _, _) =>
switch inputs {
| [IEvRecord(dict)] => dict->Internals.toList->Ok
| _ => Error(impossibleError)
@ -156,11 +156,12 @@ let library = [
FnDefinition.make(
~name="fromList",
~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))],
~run=(inputs, _, _) =>
~run=(inputs, _, _, _) => {
switch inputs {
| [IEvArray(items)] => Internals.fromList(items)
| _ => Error(impossibleError)
},
}
},
(),
),
],

View File

@ -21,7 +21,8 @@ module DistributionCreation = {
FnDefinition.make(
~name,
~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber],
~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env),
~run=(_, inputs, env, _) =>
inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env),
(),
)
}
@ -30,7 +31,7 @@ module DistributionCreation = {
FnDefinition.make(
~name,
~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])],
~run=(_, inputs, env) =>
~run=(_, inputs, env, _) =>
inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env),
(),
)
@ -40,7 +41,7 @@ module DistributionCreation = {
FnDefinition.make(
~name,
~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])],
~run=(_, inputs, env) =>
~run=(_, inputs, env, _) =>
inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env),
(),
)
@ -57,7 +58,8 @@ module DistributionCreation = {
FnDefinition.make(
~name,
~inputs=[FRTypeDistOrNumber],
~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env),
~run=(_, inputs, env, _) =>
inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env),
(),
)
}

View File

@ -51,7 +51,7 @@ let library = [
FnDefinition.make(
~name="declare",
~inputs=[Declaration.frType],
~run=(_, inputs, _) => {
~run=(_, inputs, _, _) => {
inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue)
},
(),

View File

@ -23,13 +23,67 @@ module Internals = {
let reverse = (array: array<internalExpressionValue>): internalExpressionValue => IEvArray(
Belt.Array.reverse(array),
)
let map = (array: array<internalExpressionValue>, environment, eLambdaValue, reducer): result<
ReducerInterface_InternalExpressionValue.t,
Reducer_ErrorValue.errorValue,
> => {
let rMappedList = array->E.A.reduceReverse(Ok(list{}), (rAcc, elem) =>
rAcc->E.R.bind(_, acc => {
let rNewElem = Reducer_Expression_Lambda.doLambdaCall(
eLambdaValue,
list{elem},
environment,
reducer,
)
rNewElem->E.R2.fmap(newElem => list{newElem, ...acc})
})
)
rMappedList->E.R2.fmap(mappedList => mappedList->Belt.List.toArray->Wrappers.evArray)
}
let reduce = (aValueArray, initialValue, aLambdaValue, environment, reducer) => {
aValueArray->E.A.reduce(Ok(initialValue), (rAcc, elem) =>
rAcc->E.R.bind(_, acc =>
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, environment, reducer)
)
)
}
let reduceReverse = (aValueArray, initialValue, aLambdaValue, environment, reducer) => {
aValueArray->Belt.Array.reduceReverse(Ok(initialValue), (rAcc, elem) =>
rAcc->Belt.Result.flatMap(acc =>
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, environment, reducer)
)
)
}
let filter = (aValueArray, aLambdaValue, environment, reducer) => {
let rMappedList = aValueArray->Belt.Array.reduceReverse(Ok(list{}), (rAcc, elem) =>
rAcc->E.R.bind(_, acc => {
let rNewElem = Reducer_Expression_Lambda.doLambdaCall(
aLambdaValue,
list{elem},
environment,
reducer,
)
rNewElem->E.R2.fmap(newElem => {
switch newElem {
| IEvBool(true) => list{elem, ...acc}
| _ => acc
}
})
})
)
rMappedList->E.R2.fmap(mappedList => mappedList->Belt.List.toArray->Wrappers.evArray)
}
}
let library = [
Function.make(
~name="make",
~nameSpace,
~requiresNamespace,
~requiresNamespace=true,
~output=EvtArray,
~examples=[`List.make(2, "testValue")`],
~definitions=[
@ -37,7 +91,7 @@ let library = [
FnDefinition.make(
~name="make",
~inputs=[FRTypeNumber, FRTypeAny],
~run=(inputs, _, _) => {
~run=(inputs, _, _, _) => {
switch inputs {
| [IEvNumber(number), value] => Internals.makeFromNumber(number, value)->Ok
| _ => Error(impossibleError)
@ -51,14 +105,14 @@ let library = [
Function.make(
~name="upTo",
~nameSpace,
~requiresNamespace,
~requiresNamespace=true,
~output=EvtArray,
~examples=[`List.upTo(1,4)`],
~definitions=[
FnDefinition.make(
~name="upTo",
~inputs=[FRTypeNumber, FRTypeNumber],
~run=(_, inputs, _) =>
~run=(_, inputs, _, _) =>
inputs
->Prepare.ToValueTuple.twoNumbers
->E.R2.fmap(((low, high)) => Internals.upTo(low, high)),
@ -70,13 +124,13 @@ let library = [
Function.make(
~name="first",
~nameSpace,
~requiresNamespace,
~requiresNamespace=true,
~examples=[`List.first([1,4,5])`],
~definitions=[
FnDefinition.make(
~name="first",
~inputs=[FRTypeArray(FRTypeAny)],
~run=(inputs, _, _) =>
~run=(inputs, _, _, _) =>
switch inputs {
| [IEvArray(array)] => Internals.first(array)
| _ => Error(impossibleError)
@ -89,13 +143,13 @@ let library = [
Function.make(
~name="last",
~nameSpace,
~requiresNamespace,
~requiresNamespace=true,
~examples=[`List.last([1,4,5])`],
~definitions=[
FnDefinition.make(
~name="last",
~inputs=[FRTypeArray(FRTypeAny)],
~run=(inputs, _, _) =>
~run=(inputs, _, _, _) =>
switch inputs {
| [IEvArray(array)] => Internals.last(array)
| _ => Error(impossibleError)
@ -115,7 +169,7 @@ let library = [
FnDefinition.make(
~name="reverse",
~inputs=[FRTypeArray(FRTypeAny)],
~run=(inputs, _, _) =>
~run=(inputs, _, _, _) =>
switch inputs {
| [IEvArray(array)] => Internals.reverse(array)->Ok
| _ => Error(impossibleError)
@ -125,4 +179,87 @@ let library = [
],
(),
),
Function.make(
~name="map",
~nameSpace,
~output=EvtArray,
~requiresNamespace=false,
~examples=[`List.map([1,4,5], {|x| x+1})`],
~definitions=[
FnDefinition.make(
~name="map",
~inputs=[FRTypeArray(FRTypeAny), FRTypeLambda],
~run=(inputs, _, env, reducer) =>
switch inputs {
| [IEvArray(array), IEvLambda(lambda)] =>
Internals.map(array, env, lambda, reducer)->E.R2.errMap(_ => "Error!")
| _ => Error(impossibleError)
},
(),
),
],
(),
),
Function.make(
~name="reduce",
~nameSpace,
~requiresNamespace=false,
~examples=[`List.reduce([1,4,5], 2, {|acc, el| acc+el})`],
~definitions=[
FnDefinition.make(
~name="reduce",
~inputs=[FRTypeArray(FRTypeAny), FRTypeAny, FRTypeLambda],
~run=(inputs, _, env, reducer) =>
switch inputs {
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
Internals.reduce(array, initialValue, lambda, env, reducer)->E.R2.errMap(_ => "Error!")
| _ => Error(impossibleError)
},
(),
),
],
(),
),
Function.make(
~name="reduceReverse",
~nameSpace,
~requiresNamespace=false,
~examples=[`List.reduceReverse([1,4,5], 2, {|acc, el| acc-el})`],
~definitions=[
FnDefinition.make(
~name="reduceReverse",
~inputs=[FRTypeArray(FRTypeAny), FRTypeAny, FRTypeLambda],
~run=(inputs, _, env, reducer) =>
switch inputs {
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
Internals.reduceReverse(array, initialValue, lambda, env, reducer)->E.R2.errMap(_ =>
"Error!"
)
| _ => Error(impossibleError)
},
(),
),
],
(),
),
Function.make(
~name="filter",
~nameSpace,
~requiresNamespace=false,
~examples=[`List.filter([1,4,5], {|x| x>3})`],
~definitions=[
FnDefinition.make(
~name="filter",
~inputs=[FRTypeArray(FRTypeAny), FRTypeLambda],
~run=(inputs, _, env, reducer) =>
switch inputs {
| [IEvArray(array), IEvLambda(lambda)] =>
Internals.filter(array, lambda, env, reducer)->E.R2.errMap(_ => "Error!")
| _ => Error(impossibleError)
},
(),
),
],
(),
),
]

View File

@ -9,7 +9,7 @@ module NumberToNumber = {
FnDefinition.make(
~name,
~inputs=[FRTypeNumber],
~run=(_, inputs, _) => {
~run=(_, inputs, _, _) => {
inputs
->getOrError(0)
->E.R.bind(Prepare.oneNumber)
@ -25,7 +25,7 @@ module ArrayNumberDist = {
FnDefinition.make(
~name,
~inputs=[FRTypeArray(FRTypeNumber)],
~run=(_, inputs, _) =>
~run=(_, inputs, _, _) =>
Prepare.ToTypedArray.numbers(inputs)
->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r))
->E.R.bind(fn),
@ -36,7 +36,7 @@ module ArrayNumberDist = {
FnDefinition.make(
~name,
~inputs=[FRTypeArray(FRTypeAny)],
~run=(_, inputs, _) =>
~run=(_, inputs, _, _) =>
Prepare.ToTypedArray.numbers(inputs)
->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r))
->E.R.bind(fn),

View File

@ -1,7 +1,7 @@
open FunctionRegistry_Core
open FunctionRegistry_Helpers
let nameSpace = "Pointset"
let nameSpace = "PointSet"
let requiresNamespace = true
let inputsTodist = (inputs: array<FunctionRegistry_Core.frValue>, makeDist) => {
@ -24,12 +24,41 @@ let inputsTodist = (inputs: array<FunctionRegistry_Core.frValue>, makeDist) => {
}
let library = [
Function.make(
~name="fromDist",
~nameSpace,
~requiresNamespace=true,
~examples=[`PointSet.fromDist(normal(5,2))`],
~output=ReducerInterface_InternalExpressionValue.EvtDistribution,
~definitions=[
FnDefinition.make(
~name="fromDist",
~inputs=[FRTypeDist],
~run=(_, inputs, env, _) =>
switch inputs {
| [FRValueDist(dist)] =>
GenericDist.toPointSet(
dist,
~xyPointLength=env.xyPointLength,
~sampleCount=env.sampleCount,
(),
)
->E.R2.fmap(Wrappers.pointSet)
->E.R2.fmap(Wrappers.evDistribution)
->E.R2.errMap(_ => "")
| _ => Error(impossibleError)
},
(),
),
],
(),
),
Function.make(
~name="makeContinuous",
~nameSpace,
~requiresNamespace,
~examples=[
`Pointset.makeContinuous([
`PointSet.makeContinuous([
{x: 0, y: 0.2},
{x: 1, y: 0.7},
{x: 2, y: 0.8},
@ -41,7 +70,7 @@ let library = [
FnDefinition.make(
~name="makeContinuous",
~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))],
~run=(_, inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))),
~run=(_, inputs, _, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))),
(),
),
],
@ -52,7 +81,7 @@ let library = [
~nameSpace,
~requiresNamespace,
~examples=[
`Pointset.makeDiscrete([
`PointSet.makeDiscrete([
{x: 0, y: 0.2},
{x: 1, y: 0.7},
{x: 2, y: 0.8},
@ -64,7 +93,7 @@ let library = [
FnDefinition.make(
~name="makeDiscrete",
~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))],
~run=(_, inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))),
~run=(_, inputs, _, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))),
(),
),
],

View File

@ -0,0 +1,272 @@
open FunctionRegistry_Core
open FunctionRegistry_Helpers
let nameSpace = "SampleSet"
let requiresNamespace = true
module Internal = {
type t = SampleSetDist.t
let doLambdaCall = (aLambdaValue, list, environment, reducer) =>
switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, environment, reducer) {
| Ok(IEvNumber(f)) => Ok(f)
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
}
let toType = (r): result<
ReducerInterface_InternalExpressionValue.t,
Reducer_ErrorValue.errorValue,
> =>
switch r {
| Ok(r) => Ok(Wrappers.evDistribution(SampleSet(r)))
| Error(r) => Error(REDistributionError(SampleSetError(r)))
}
//TODO: I don't know why this seems to need at least one input
let fromFn = (
aLambdaValue,
env: ReducerInterface_InternalExpressionValue.environment,
reducer,
) => {
let sampleCount = env.sampleCount
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, env, reducer)
Belt_Array.makeBy(sampleCount, r => fn(r->Js.Int.toFloat))->E.A.R.firstErrorOrOpen
}
let map1 = (sampleSetDist: t, aLambdaValue, env, reducer) => {
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)}, env, reducer)
SampleSetDist.samplesMap(~fn, sampleSetDist)->toType
}
let map2 = (t1: t, t2: t, aLambdaValue, env, reducer) => {
let fn = (a, b) => doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b)}, env, reducer)
SampleSetDist.map2(~fn, ~t1, ~t2)->toType
}
let map3 = (t1: t, t2: t, t3: t, aLambdaValue, env, reducer) => {
let fn = (a, b, c) =>
doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b), IEvNumber(c)}, env, reducer)
SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType
}
let parseSampleSetArray = (arr: array<internalExpressionValue>): option<
array<SampleSetDist.t>,
> => {
let parseSampleSet = (value: internalExpressionValue): option<SampleSetDist.t> =>
switch value {
| IEvDistribution(SampleSet(dist)) => Some(dist)
| _ => None
}
E.A.O.openIfAllSome(E.A.fmap(parseSampleSet, arr))
}
let mapN = (aValueArray: array<internalExpressionValue>, aLambdaValue, env, reducer) => {
switch parseSampleSetArray(aValueArray) {
| Some(t1) =>
let fn = a =>
doLambdaCall(
aLambdaValue,
list{IEvArray(E.A.fmap(x => Wrappers.evNumber(x), a))},
env,
reducer,
)
SampleSetDist.mapN(~fn, ~t1)->toType
| None => Error(REFunctionNotFound(""))
}
}
}
let library = [
Function.make(
~name="fromDist",
~nameSpace,
~requiresNamespace=true,
~examples=[`SampleSet.fromDist(normal(5,2))`],
~output=ReducerInterface_InternalExpressionValue.EvtDistribution,
~definitions=[
FnDefinition.make(
~name="fromDist",
~inputs=[FRTypeDist],
~run=(_, inputs, env, _) =>
switch inputs {
| [FRValueDist(dist)] =>
GenericDist.toSampleSetDist(dist, env.sampleCount)
->E.R2.fmap(Wrappers.sampleSet)
->E.R2.fmap(Wrappers.evDistribution)
->E.R2.errMap(_ => "")
| _ => Error(impossibleError)
},
(),
),
],
(),
),
Function.make(
~name="fromList",
~nameSpace,
~requiresNamespace=true,
~examples=[`SampleSet.fromList([3,5,2,3,5,2,3,5,2,3,3,5,3,2,3,1,1,3])`],
~output=ReducerInterface_InternalExpressionValue.EvtDistribution,
~definitions=[
FnDefinition.make(
~name="fromList",
~inputs=[FRTypeArray(FRTypeNumber)],
~run=(_, inputs, _, _) => {
let sampleSet =
Prepare.ToTypedArray.numbers(inputs) |> E.R2.bind(r =>
SampleSetDist.make(r)->E.R2.errMap(_ => "AM I HERE? WHYERE AMI??")
)
sampleSet->E.R2.fmap(Wrappers.sampleSet)->E.R2.fmap(Wrappers.evDistribution)
},
(),
),
],
(),
),
Function.make(
~name="toList",
~nameSpace,
~requiresNamespace=true,
~examples=[`SampleSet.toList(SampleSet.fromDist(normal(5,2)))`],
~output=ReducerInterface_InternalExpressionValue.EvtArray,
~definitions=[
FnDefinition.make(
~name="toList",
~inputs=[FRTypeDist],
~run=(inputs, _, _, _) =>
switch inputs {
| [IEvDistribution(SampleSet(dist))] =>
dist->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok
| _ => Error(impossibleError)
},
(),
),
],
(),
),
Function.make(
~name="fromFn",
~nameSpace,
~requiresNamespace=true,
~examples=[`SampleSet.fromFn({|| sample(normal(5,2))})`],
~output=ReducerInterface_InternalExpressionValue.EvtDistribution,
~definitions=[
FnDefinition.make(
~name="fromFn",
~inputs=[FRTypeLambda],
~run=(inputs, _, env, reducer) =>
switch inputs {
| [IEvLambda(lambda)] =>
switch Internal.fromFn(lambda, env, reducer) {
| Ok(r) => Ok(r->Wrappers.sampleSet->Wrappers.evDistribution)
| Error(_) => Error("issue")
}
| _ => Error(impossibleError)
},
(),
),
],
(),
),
Function.make(
~name="map",
~nameSpace,
~requiresNamespace,
~examples=[`SampleSet.map(SampleSet.fromDist(normal(5,2)), {|x| x + 1})`],
~output=ReducerInterface_InternalExpressionValue.EvtDistribution,
~definitions=[
FnDefinition.make(
~name="map",
~inputs=[FRTypeDist, FRTypeLambda],
~run=(inputs, _, env, reducer) =>
switch inputs {
| [IEvDistribution(SampleSet(dist)), IEvLambda(lambda)] =>
Internal.map1(dist, lambda, env, reducer)->E.R2.errMap(_ => "")
| _ => Error(impossibleError)
},
(),
),
],
(),
),
Function.make(
~name="map2",
~nameSpace,
~requiresNamespace,
~examples=[
`SampleSet.map2(SampleSet.fromDist(normal(5,2)), SampleSet.fromDist(normal(5,2)), {|x, y| x + y})`,
],
~output=ReducerInterface_InternalExpressionValue.EvtDistribution,
~definitions=[
FnDefinition.make(
~name="map2",
~inputs=[FRTypeDist, FRTypeDist, FRTypeLambda],
~run=(inputs, _, env, reducer) => {
switch inputs {
| [
IEvDistribution(SampleSet(dist1)),
IEvDistribution(SampleSet(dist2)),
IEvLambda(lambda),
] =>
Internal.map2(dist1, dist2, lambda, env, reducer)->E.R2.errMap(_ => "")
| _ => Error(impossibleError)
}
},
(),
),
],
(),
),
Function.make(
~name="map3",
~nameSpace,
~requiresNamespace,
~examples=[
`SampleSet.map3(SampleSet.fromDist(normal(5,2)), SampleSet.fromDist(normal(5,2)), SampleSet.fromDist(normal(5,2)), {|x, y, z| max([x,y,z])})`,
],
~output=ReducerInterface_InternalExpressionValue.EvtDistribution,
~definitions=[
FnDefinition.make(
~name="map3",
~inputs=[FRTypeDist, FRTypeDist, FRTypeDist, FRTypeLambda],
~run=(inputs, _, env, reducer) =>
switch inputs {
| [
IEvDistribution(SampleSet(dist1)),
IEvDistribution(SampleSet(dist2)),
IEvDistribution(SampleSet(dist3)),
IEvLambda(lambda),
] =>
Internal.map3(dist1, dist2, dist3, lambda, env, reducer)->E.R2.errMap(_ => "")
| _ => Error(impossibleError)
},
(),
),
],
(),
),
Function.make(
~name="mapN",
~nameSpace,
~requiresNamespace,
~examples=[
`SampleSet.mapN([SampleSet.fromDist(normal(5,2)), SampleSet.fromDist(normal(5,2)), SampleSet.fromDist(normal(5,2))], {|x| max(x)})`,
],
~output=ReducerInterface_InternalExpressionValue.EvtDistribution,
~definitions=[
FnDefinition.make(
~name="mapN",
~inputs=[FRTypeArray(FRTypeDist), FRTypeLambda],
~run=(inputs, _, env, reducer) =>
switch inputs {
| [IEvArray(dists), IEvLambda(lambda)] =>
Internal.mapN(dists, lambda, env, reducer)->E.R2.errMap(_e => {
"AHHH doesn't work"
})
| _ => Error(impossibleError)
},
(),
),
],
(),
),
]

View File

@ -30,7 +30,7 @@ let library = [
("prior", FRTypeDist),
]),
],
~run=(_, inputs, env) => {
~run=(_, inputs, env, _) => {
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) {
| Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d)), FRValueDist(prior)]) =>
runScoring(estimate, Score_Dist(d), Some(prior), env)
@ -49,7 +49,7 @@ let library = [
FnDefinition.make(
~name="logScore",
~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])],
~run=(_, inputs, env) => {
~run=(_, inputs, env, _) => {
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) {
| Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) =>
runScoring(estimate, Score_Dist(d), None, env)
@ -74,7 +74,7 @@ let library = [
FnDefinition.make(
~name="klDivergence",
~inputs=[FRTypeDist, FRTypeDist],
~run=(_, inputs, env) => {
~run=(_, inputs, env, _) => {
switch inputs {
| [FRValueDist(estimate), FRValueDist(d)] =>
runScoring(estimate, Score_Dist(d), None, env)

View File

@ -95,33 +95,7 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
let doExportBindings = (bindings: nameSpace) => bindings->Bindings.toExpressionValue->Ok
let doKeepArray = (aValueArray, aLambdaValue) => {
let rMappedList = aValueArray->Belt.Array.reduceReverse(Ok(list{}), (rAcc, elem) =>
rAcc->Result.flatMap(acc => {
let rNewElem = Lambda.doLambdaCall(aLambdaValue, list{elem}, environment, reducer)
rNewElem->Result.map(newElem =>
switch newElem {
| IEvBool(true) => list{elem, ...acc}
| _ => acc
}
)
})
)
rMappedList->Result.map(mappedList => mappedList->Belt.List.toArray->IEvArray)
}
let doMapArray = (aValueArray, aLambdaValue) => {
let rMappedList = aValueArray->Belt.Array.reduceReverse(Ok(list{}), (rAcc, elem) =>
rAcc->Result.flatMap(acc => {
let rNewElem = Lambda.doLambdaCall(aLambdaValue, list{elem}, environment, reducer)
rNewElem->Result.map(newElem => list{newElem, ...acc})
})
)
rMappedList->Result.map(mappedList => mappedList->Belt.List.toArray->IEvArray)
}
module SampleMap = {
type t = SampleSetDist.t
let doLambdaCall = (aLambdaValue, list) =>
switch Lambda.doLambdaCall(aLambdaValue, list, environment, reducer) {
| Ok(IEvNumber(f)) => Ok(f)
@ -134,22 +108,6 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
| Error(r) => Error(REDistributionError(SampleSetError(r)))
}
let map1 = (sampleSetDist: t, aLambdaValue) => {
let fn = r => doLambdaCall(aLambdaValue, list{IEvNumber(r)})
toType(SampleSetDist.samplesMap(~fn, sampleSetDist))
}
let map2 = (t1: t, t2: t, aLambdaValue) => {
let fn = (a, b) => doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b)})
SampleSetDist.map2(~fn, ~t1, ~t2)->toType
}
let map3 = (t1: t, t2: t, t3: t, aLambdaValue) => {
let fn = (a, b, c) =>
doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b), IEvNumber(c)})
SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType
}
let parseSampleSetArray = (arr: array<internalExpressionValue>): option<
array<SampleSetDist.t>,
> => {
@ -161,7 +119,7 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
E.A.O.openIfAllSome(E.A.fmap(parseSampleSet, arr))
}
let mapN = (aValueArray: array<internalExpressionValue>, aLambdaValue) => {
let _mapN = (aValueArray: array<internalExpressionValue>, aLambdaValue) => {
switch parseSampleSetArray(aValueArray) {
| Some(t1) =>
let fn = a => doLambdaCall(aLambdaValue, list{IEvArray(E.A.fmap(x => IEvNumber(x), a))})
@ -172,22 +130,6 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
}
}
let doReduceArray = (aValueArray, initialValue, aLambdaValue) => {
aValueArray->Belt.Array.reduce(Ok(initialValue), (rAcc, elem) =>
rAcc->Result.flatMap(acc =>
Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, environment, reducer)
)
)
}
let doReduceReverseArray = (aValueArray, initialValue, aLambdaValue) => {
aValueArray->Belt.Array.reduceReverse(Ok(initialValue), (rAcc, elem) =>
rAcc->Result.flatMap(acc =>
Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, environment, reducer)
)
)
}
switch call {
| ("$_atIndex_$", [IEvArray(aValueArray), IEvNumber(fIndex)]) => arrayAtIndex(aValueArray, fIndex)
| ("$_atIndex_$", [IEvBindings(dict), IEvString(sIndex)]) => moduleAtIndex(dict, sIndex)
@ -226,38 +168,6 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
doAddString(aValueString, bValueString)
| ("inspect", [value, IEvString(label)]) => inspectLabel(value, label)
| ("inspect", [value]) => inspect(value)
| ("filter", [IEvArray(aValueArray), IEvLambda(aLambdaValue)]) =>
doKeepArray(aValueArray, aLambdaValue)
| ("map", [IEvArray(aValueArray), IEvLambda(aLambdaValue)]) =>
doMapArray(aValueArray, aLambdaValue)
| ("mapSamples", [IEvDistribution(SampleSet(dist)), IEvLambda(aLambdaValue)]) =>
SampleMap.map1(dist, aLambdaValue)
| (
"mapSamples2",
[
IEvDistribution(SampleSet(dist1)),
IEvDistribution(SampleSet(dist2)),
IEvLambda(aLambdaValue),
],
) =>
SampleMap.map2(dist1, dist2, aLambdaValue)
| (
"mapSamples3",
[
IEvDistribution(SampleSet(dist1)),
IEvDistribution(SampleSet(dist2)),
IEvDistribution(SampleSet(dist3)),
IEvLambda(aLambdaValue),
],
) =>
SampleMap.map3(dist1, dist2, dist3, aLambdaValue)
| ("mapSamplesN", [IEvArray(aValueArray), IEvLambda(aLambdaValue)]) =>
SampleMap.mapN(aValueArray, aLambdaValue)
| ("reduce", [IEvArray(aValueArray), initialValue, IEvLambda(aLambdaValue)]) =>
doReduceArray(aValueArray, initialValue, aLambdaValue)
| ("reduceReverse", [IEvArray(aValueArray), initialValue, IEvLambda(aLambdaValue)]) =>
doReduceReverseArray(aValueArray, initialValue, aLambdaValue)
| ("reverse", [IEvArray(aValueArray)]) => aValueArray->Belt.Array.reverse->IEvArray->Ok
| (_, [IEvBool(_)])
| (_, [IEvNumber(_)])
| (_, [IEvString(_)])

View File

@ -82,3 +82,5 @@ let eIdentifier = (name: string): expression =>
let eTypeIdentifier = (name: string): expression =>
name->BInternalExpressionValue.IEvTypeIdentifier->BExpressionT.EValue
let eVoid: expression = BInternalExpressionValue.IEvVoid->BExpressionT.EValue

View File

@ -5,13 +5,12 @@
}}
start
// = _nl start:typeExpression _nl finalComment? {return start}
= _nl start:outerBlock _nl finalComment? {return start}
zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda
outerBlock
= statements:array_statements finalExpression: (statementSeparator @expression)?
= statements:array_statements finalExpression: (statementSeparator @expression)?
{ if (finalExpression != null) { statements.push(finalExpression) }
return h.nodeBlock(statements) }
/ finalExpression: expression
@ -24,25 +23,31 @@ innerBlockOrExpression
quotedInnerBlock
= '{' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
{ statements.push(finalExpression)
return h.nodeBlock(statements) }
{ statements.push(finalExpression)
return h.nodeBlock(statements) }
/ '{' _nl finalExpression: expression _nl '}'
{ return h.nodeBlock([finalExpression]) }
{ return h.nodeBlock([finalExpression]) }
array_statements
= head:statement tail:(statementSeparator @array_statements )
{ return [head, ...tail] }
/ head:statement
{ return [head] }
{ return [head] }
statement
= letStatement
/ defunStatement
/ typeStatement
/ voidStatement
voidStatement
= "call" _nl value:zeroOMoreArgumentsBlockOrExpression
{ var variable = h.nodeIdentifier("_", location());
return h.nodeLetStatement(variable, value); }
letStatement
= variable:identifier _ assignmentOp _nl value:zeroOMoreArgumentsBlockOrExpression
{ return h.nodeLetStatement(variable, value) }
{ return h.nodeLetStatement(variable, value) }
defunStatement
= variable:identifier '(' _nl args:array_parameters _nl ')' _ assignmentOp _nl body:innerBlockOrExpression
@ -53,13 +58,15 @@ defunStatement
array_parameters
= head:dollarIdentifier tail:(_ ',' _nl @dollarIdentifier)*
{ return [head, ...tail]; }
{ return [head, ...tail]; }
/ ""
{ return [h.nodeIdentifier("_", location())]; }
expression = ifthenelse / ternary / logicalAdditive
ifthenelse
= 'if' __nl condition:logicalAdditive
__nl 'then' __nl trueExpression:innerBlockOrExpression
__nl 'then' __nl trueExpression:innerBlockOrExpression
__nl 'else' __nl falseExpression:(ifthenelse/innerBlockOrExpression)
{ return h.nodeTernary(condition, trueExpression, falseExpression) }
@ -89,7 +96,7 @@ equality
{ return h.makeFunctionCall(h.toFunction[operator], [left, right])}
/ relational
equalityOp "operator" = '=='/'!='
equalityOp "operator" = '=='/'!='
relational
= left:additive _ operator:relationalOp _nl right:additive
@ -172,6 +179,8 @@ collectionElement
array_functionArguments
= head:expression tail:(_ ',' _nl @expression)*
{ return [head, ...tail]; }
/ ""
{return [h.nodeVoid()];}
atom
= '(' _nl expression:expression _nl ')' {return expression}
@ -185,6 +194,10 @@ basicLiteral
/ boolean
/ dollarIdentifierWithModule
/ dollarIdentifier
/ voidLiteral
voidLiteral 'void'
= "()" {return h.nodeVoid();}
dollarIdentifierWithModule 'identifier'
= head:$moduleIdentifier
@ -195,7 +208,7 @@ dollarIdentifierWithModule 'identifier'
modifiers.unshift(head)
modifiers.push(final)
let modifiedIdentifier = modifiers.join('.')
return h.nodeIdentifier(modifiedIdentifier)
return h.nodeIdentifier(modifiedIdentifier, location())
}
identifier 'identifier'
@ -232,8 +245,8 @@ float 'float'
= $(((d+ "\." d*) / ("\." d+)) floatExponent? / d+ floatExponent)
{ return h.nodeFloat(parseFloat(text()))}
floatExponent = [e]i '-'? d+
d = [0-9]
floatExponent = [e]i '-'? d+
d = [0-9]
boolean 'boolean'
= ('true'/'false')
@ -247,10 +260,10 @@ valueConstructor
lambda
= '{' _nl '|' _nl args:array_parameters _nl '|' _nl statements:array_statements finalExpression: (statementSeparator @expression) _nl '}'
{ statements.push(finalExpression)
return h.nodeLambda(args, h.nodeBlock(statements)) }
{ statements.push(finalExpression)
return h.nodeLambda(args, h.nodeBlock(statements)) }
/ '{' _nl '|' _nl args:array_parameters _nl '|' _nl finalExpression: expression _nl '}'
{ return h.nodeLambda(args, h.nodeBlock([finalExpression])) }
{ return h.nodeLambda(args, h.nodeBlock([finalExpression])) }
arrayConstructor 'array'
= '[' _nl ']'
@ -289,7 +302,7 @@ __nl 'whitespace or newline'
= (whiteSpaceCharactersOrComment / commentOrNewLine )+
statementSeparator 'statement separator'
= _ (';'/ commentOrNewLine)+ _nl
= _ (';'/ commentOrNewLine)+ _nl
commentOrNewLine = finalComment? newLine

View File

@ -34,6 +34,7 @@ type nodeModuleIdentifier = {...node, "value": string}
type nodeString = {...node, "value": string}
type nodeTernary = {...node, "condition": node, "trueExpression": node, "falseExpression": node}
type nodeTypeIdentifier = {...node, "value": string}
type nodeVoid = node
type peggyNode =
| PgNodeBlock(nodeBlock)
@ -50,6 +51,7 @@ type peggyNode =
| PgNodeString(nodeString)
| PgNodeTernary(nodeTernary)
| PgNodeTypeIdentifier(nodeTypeIdentifier)
| PgNodeVoid(nodeVoid)
external castNodeBlock: node => nodeBlock = "%identity"
external castNodeBoolean: node => nodeBoolean = "%identity"
@ -65,6 +67,7 @@ external castNodeModuleIdentifier: node => nodeModuleIdentifier = "%identity"
external castNodeString: node => nodeString = "%identity"
external castNodeTernary: node => nodeTernary = "%identity"
external castNodeTypeIdentifier: node => nodeTypeIdentifier = "%identity"
external castNodeVoid: node => nodeVoid = "%identity"
exception UnsupportedPeggyNodeType(string) // This should never happen; programming error
let castNodeType = (node: node) =>
@ -83,6 +86,7 @@ let castNodeType = (node: node) =>
| "String" => node->castNodeString->PgNodeString
| "Ternary" => node->castNodeTernary->PgNodeTernary
| "TypeIdentifier" => node->castNodeTypeIdentifier->PgNodeTypeIdentifier
| "Void" => node->castNodeVoid->PgNodeVoid
| _ => raise(UnsupportedPeggyNodeType(node["type"]))
}
@ -116,6 +120,7 @@ let rec pgToString = (peggyNode: peggyNode): string => {
" " ++
toString(node["falseExpression"]) ++ ")"
| PgNodeTypeIdentifier(node) => `#${node["value"]}`
| PgNodeVoid(_node) => "()"
}
}
and toString = (node: node): string => node->castNodeType->pgToString

View File

@ -48,5 +48,6 @@ let rec fromNode = (node: Parse.node): expression => {
)
| PgNodeTypeIdentifier(nodeTypeIdentifier) =>
ExpressionBuilder.eTypeIdentifier(nodeTypeIdentifier["value"])
| PgNodeVoid(_) => ExpressionBuilder.eVoid
}
}

View File

@ -213,3 +213,7 @@ export function nodeTernary(
export function nodeTypeIdentifier(typeValue: string) {
return { type: "TypeIdentifier", value: typeValue };
}
export function nodeVoid() {
return { type: "Void" };
}

View File

@ -25,6 +25,7 @@ type rec externalExpressionValue =
| EvTypeIdentifier(string)
| EvModule(record)
| EvType(record)
| EvVoid
and record = Js.Dict.t<externalExpressionValue>
and externalBindings = record
and lambdaValue = {
@ -63,6 +64,7 @@ let rec toString = aValue =>
| EvTimeDuration(t) => DateTime.Duration.toString(t)
| EvType(t) => `type${t->toStringRecord}`
| EvTypeIdentifier(id) => `#${id}`
| EvVoid => `()`
}
and toStringRecord = aRecord => {
let pairs =

View File

@ -4,16 +4,18 @@ type internalExpressionValue = InternalExpressionValue.t
/*
Map external calls of Reducer
*/
let dispatch = (call: InternalExpressionValue.functionCall, environment, reducer, chain): result<
internalExpressionValue,
'e,
> => {
let dispatch = (
call: InternalExpressionValue.functionCall,
environment,
reducer: Reducer_Expression_T.reducerFn,
chain,
): result<internalExpressionValue, 'e> => {
E.A.O.firstSomeFn([
() => ReducerInterface_GenericDistribution.dispatch(call, environment),
() => ReducerInterface_Date.dispatch(call, environment),
() => ReducerInterface_Duration.dispatch(call, environment),
() => ReducerInterface_Number.dispatch(call, environment),
() => FunctionRegistry_Library.dispatch(call, environment),
() => FunctionRegistry_Library.dispatch(call, environment, reducer),
])->E.O2.default(chain(call, environment, reducer))
}

View File

@ -233,19 +233,6 @@ let dispatchToGenericOutput = (call: IEV.functionCall, env: GenericDist.env): op
| ("inv", [IEvDistribution(dist), IEvNumber(float)]) => Helpers.toFloatFn(#Inv(float), dist, ~env)
| ("quantile", [IEvDistribution(dist), IEvNumber(float)]) =>
Helpers.toFloatFn(#Inv(float), dist, ~env)
| ("toSampleSet", [IEvDistribution(dist), IEvNumber(float)]) =>
Helpers.toDistFn(ToSampleSet(Belt.Int.fromFloat(float)), dist, ~env)
| ("toSampleSet", [IEvDistribution(dist)]) =>
Helpers.toDistFn(ToSampleSet(env.sampleCount), dist, ~env)
| ("toList", [IEvDistribution(SampleSet(dist))]) => Some(FloatArray(SampleSetDist.T.get(dist)))
| ("fromSamples", [IEvArray(inputArray)]) => {
let _wrapInputErrors = x => SampleSetDist.NonNumericInput(x)
let parsedArray = Helpers.parseNumberArray(inputArray)->E.R2.errMap(_wrapInputErrors)
switch parsedArray {
| Ok(array) => DistributionOperation.run(FromSamples(array), ~env)
| Error(e) => GenDistError(SampleSetError(e))
}->Some
}
| ("inspect", [IEvDistribution(dist)]) => Helpers.toDistFn(Inspect, dist, ~env)
| ("truncateLeft", [IEvDistribution(dist), IEvNumber(float)]) =>
Helpers.toDistFn(Truncate(Some(float), None), dist, ~env)

View File

@ -23,6 +23,7 @@ type rec t =
| IEvTimeDuration(float)
| IEvType(map)
| IEvTypeIdentifier(string)
| IEvVoid
and map = Belt.Map.String.t<t>
and nameSpace = NameSpace(Belt.Map.String.t<t>)
and lambdaValue = {
@ -60,6 +61,7 @@ let rec toString = aValue =>
| IEvType(aMap) => aMap->toStringMap
| IEvTimeDuration(t) => DateTime.Duration.toString(t)
| IEvTypeIdentifier(id) => `#${id}`
| IEvVoid => `()`
}
and toStringMap = aMap => {
let pairs =
@ -92,6 +94,7 @@ let toStringWithType = aValue =>
| IEvTimeDuration(_) => `Date::${toString(aValue)}`
| IEvType(_) => `Type::${toString(aValue)}`
| IEvTypeIdentifier(_) => `TypeIdentifier::${toString(aValue)}`
| IEvVoid => `Void`
}
let argsToString = (args: array<t>): string => {
@ -135,6 +138,7 @@ type internalExpressionValueType =
| EvtTimeDuration
| EvtType
| EvtTypeIdentifier
| EvtVoid
type functionCallSignature = CallSignature(string, array<internalExpressionValueType>)
type functionDefinitionSignature =
@ -158,6 +162,7 @@ let valueToValueType = value =>
| IEvTimeDuration(_) => EvtTimeDuration
| IEvType(_) => EvtType
| IEvTypeIdentifier(_) => EvtTypeIdentifier
| IEvVoid => EvtVoid
}
let externalValueToValueType = (value: ExternalExpressionValue.t) =>
@ -178,6 +183,7 @@ let externalValueToValueType = (value: ExternalExpressionValue.t) =>
| EvTimeDuration(_) => EvtTimeDuration
| EvType(_) => EvtType
| EvTypeIdentifier(_) => EvtTypeIdentifier
| EvVoid => EvtVoid
}
let functionCallToCallSignature = (functionCall: functionCall): functionCallSignature => {
@ -203,6 +209,7 @@ let valueTypeToString = (valueType: internalExpressionValueType): string =>
| EvtTimeDuration => `Duration`
| EvtType => `Type`
| EvtTypeIdentifier => `TypeIdentifier`
| EvtVoid => `Void`
}
let functionCallSignatureToString = (functionCallSignature: functionCallSignature): string => {
@ -232,6 +239,7 @@ let rec toExternal = (iev: t): ExternalExpressionValue.t => {
| IEvType(v) => v->mapToExternal->EvType
| IEvTypeIdentifier(v) => EvTypeIdentifier(v)
| IEvBindings(v) => v->nameSpaceToTypeScriptBindings->EvModule
| IEvVoid => EvVoid
}
}
and mapToExternal = v =>
@ -271,6 +279,7 @@ let rec toInternal = (ev: ExternalExpressionValue.t): t => {
| EvTimeDuration(v) => IEvTimeDuration(v)
| EvType(v) => v->recordToInternal->IEvType
| EvTypeIdentifier(v) => IEvTypeIdentifier(v)
| EvVoid => IEvVoid
}
}
and recordToInternal = v =>

View File

@ -1,6 +1,6 @@
module Bindings = Reducer_Bindings
let internalStdLib = Bindings.emptyBindings->SquiggleLibrary_Math.makeBindings
let internalStdLib = Bindings.emptyBindings->SquiggleLibrary_Math.makeBindings->SquiggleLibrary_Versions.makeBindings
@genType
let externalStdLib = internalStdLib->Bindings.toTypeScriptBindings

View File

@ -0,0 +1,9 @@
module Bindings = Reducer_Bindings
let bindings: Bindings.t =
[
("System.version", ReducerInterface_InternalExpressionValue.IEvString("0.2.12")),
]->Bindings.fromArray
let makeBindings = (previousBindings: Bindings.t): Bindings.t =>
previousBindings->Bindings.merge(bindings)

View File

@ -546,6 +546,7 @@ module A = {
let slice = Belt.Array.slice
let init = Array.init
let reduce = Belt.Array.reduce
let reduceReverse = Belt.Array.reduceReverse
let reducei = Belt.Array.reduceWithIndex
let some = Belt.Array.some
let isEmpty = r => length(r) < 1

View File

@ -5,16 +5,14 @@ title: Date
Squiggle date types are a very simple implementation on [Javascript's Date type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date). It's mainly here for early experimentation. There are more relevant functions for the [Duration](/docs/Api/Duration) type.
### makeFromYear
(Now `makeDateFromYear`)
### fromYear
```
Date.makeFromYear: (number) => date
Date.fromYear: (number) => date
```
```js
makeFromYear(2022.32);
Date.fromYear(2022.32);
```
### toString
@ -30,7 +28,7 @@ add: (date, duration) => date
```
```js
makeFromYear(2022.32) + years(5);
Date.fromYear(2022.32) + years(5);
```
### subtract
@ -41,6 +39,6 @@ subtract: (date, duration) => date
```
```js
makeFromYear(2040) - makeFromYear(2020); // 20 years
makeFromYear(2040) - years(20); // 2020
Date.fromYear(2040) - Date.fromYear(2020); // 20 years
Date.fromYear(2040) - years(20); // 2020
```

View File

@ -290,38 +290,6 @@ quantile: (distribution, number) => number
quantile(normal(5, 2), 0.5);
```
### toPointSet
**TODO: Will soon be called "PointSet.make"**
Converts a distribution to the pointSet format.
```
toPointSet: (distribution) => pointSetDistribution
```
**Examples**
```javascript
toPointSet(normal(5, 2));
```
### toSampleSet
**TODO: Will soon be called "SampleSet.make"**
Converts a distribution to the sampleSet format, with n samples.
```
toSampleSet: (distribution, number) => sampleSetDistribution
```
**Examples**
```javascript
toSampleSet(normal(5, 2), 1000);
```
### truncateLeft
Truncates the left side of a distribution. Returns either a pointSet distribution or a symbolic distribution.
@ -364,6 +332,26 @@ klDivergence: (distribution, distribution) => number
klDivergence(normal(5, 2), normal(5, 4)); // returns 0.57
```
### logScore
A log loss score. Often that often acts as a [scoring rule](https://en.wikipedia.org/wiki/Scoring_rule). Useful when evaluating the accuracy of a forecast.
Note that it is fairly slow.
```
logScore: ({estimate: distribution, ?prior: distribution, answer: distribution|number}) => number
```
**Examples**
```javascript
Dist.logScore({
estimate: normal(5, 2),
answer: normal(4.5, 1.2),
prior: normal(6, 4),
}); // returns -0.597.57
```
## Display
### toString
@ -392,20 +380,6 @@ sparkline: (distribution, n = 20) => string
toSparkline(truncateLeft(normal(5, 2), 3), 20); // produces ▁▇█████▇▅▄▃▂▂▁▁▁▁▁▁▁
```
### inspect
Prints the value of the distribution to the Javascript console, then returns the distribution. Useful for debugging.
```
inspect: (distribution) => distribution
```
**Examples**
```javascript
inspect(normal(5, 2)); // logs "normal(5, 2)" to the javascript console and returns the distribution.
```
## Normalization
There are some situations where computation will return unnormalized distributions. This means that their cumulative sums are not equal to 1.0. Unnormalized distributions are not valid for many relevant functions; for example, klDivergence and scoring.
@ -414,7 +388,7 @@ The only functions that do not return normalized distributions are the pointwise
### normalize
Normalize a distribution. This means scaling it appropriately so that it's cumulative sum is equal to 1.
Normalize a distribution. This means scaling it appropriately so that it's cumulative sum is equal to 1. This only impacts Pointset distributions, because those are the only ones that can be non-normlized.
```
normalize: (distribution) => distribution
@ -606,75 +580,3 @@ dotPow: (distributionLike, distributionLike) => distribution
```
dotExp: (distributionLike, distributionLike) => distribution
```
## Scale Arithmetic Operations
<Admonition type="caution" title="Likely to change">
<p>
We're planning on removing scale operations in favor of more general
functions soon.
</p>
</Admonition>
Scale operations are similar to pointwise operations, but operate on a constant y-value instead of y-values coming from a distribution. You can think about this as scaling a distribution vertically by a constant.
The following items would be equivalent.
```js
scalePow(normal(5,2), 2)
mapY(normal(5,2), {|y| y ^ 2}) // Not yet available
```
### scaleMultiply
```
scaleMultiply: (distributionLike, number) => distribution
```
### scalePow
```
scalePow: (distributionLike, number) => distribution
```
### scaleExp
```
scaleExp: (distributionLike, number) => distribution
```
### scaleLog
```
scaleLog: (distributionLike, number) => distribution
```
### scaleLog10
```
scaleLog10: (distributionLike, number) => distribution
```
## Special
### Declaration (Continuous Functions)
Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making formal predictions. It allows you to limit the domain that your prediction will be used and scored within.
Declarations are currently experimental and will likely be removed or changed in the future.
```
declareFn: (dict<{fn: lambda, inputs: array<dict<{min: number, max: number}>>}>) => declaration
```
**Examples**
```javascript
declareFn({
fn: {|a,b| a },
inputs: [
{min: 0, max: 100},
{min: 30, max: 50}
]
})
```

View File

@ -3,26 +3,20 @@ sidebar_position: 4
title: Point Set Distribution
---
:::danger
These functions aren't yet implemented with these specific names. This should be changed soon
:::
Point set distributions are one of the three distribution formats. They are stored as a list of x-y coordinates representing both discrete and continuous distributions.
One complication is that it's possible to represent invalid probability distributions in the point set format. For example, you can represent shapes with negative values, or shapes that are not normalized.
### make
### fromDist
Converts the distribution in question into a point set distribution. If the distribution is symbolic, then it does this by taking the quantiles. If the distribution is a sample set, then it uses a version of kernel density estimation to approximate the point set format. One complication of this latter process is that if there is a high proportion of overlapping samples (samples that are exactly the same as each other), it will convert these samples into discrete point masses. Eventually we'd like to add further methods to help adjust this process.
```
PointSet.make: (distribution) => pointSetDist
PointSet.fromDist: (distribution) => pointSetDist
```
### makeContinuous
**TODO: Now called "toContinuousPointSet"**
Converts a set of x-y coordinates directly into a continuous distribution.
```
@ -40,10 +34,6 @@ PointSet.makeContinuous([
### makeDiscrete
**TODO: Now called "toDiscretePointSet"**
Converts a set of x-y coordinates directly into a discrete distribution.
```
PointSet.makeDiscrete: (list<{x: number, y: number}>) => pointSetDist
```

View File

@ -3,22 +3,42 @@ sidebar_position: 5
title: Sample Set Distribution
---
:::danger
These functions aren't yet implemented with these specific names. This should be added soon.
:::
Sample set distributions are one of the three distribution formats. Internally, they are stored as a list of numbers. It's useful to distinguish point set distributions from arbitrary lists of numbers to make it clear which functions are applicable.
Monte Carlo calculations typically result in sample set distributions.
All regular distribution function work on sample set distributions. In addition, there are several functions that only work on sample set distributions.
### make
### fromDist
```
SampleSet.make: (distribution) => sampleSet
SampleSet.make: (list<number>) => sampleSet
SampleSet.make: (() => number) => sampleSet // not yet implemented
SampleSet.fromDist: (list<number>) => sampleSet
```
### fromList
```
SampleSet.fromList: (list<number>) => sampleSet
```
### fromFn
```
SampleSet.fromFn: ((float) => number) => sampleSet
```
### toList
```
SampleSet.toList: (sampleSet) => list<number>
```
Gets the internal samples of a sampleSet distribution. This is separate from the sampleN() function, which would shuffle the samples. toList() maintains order and length.
**Examples**
```
toList(toSampleSet(normal(5,2)))
```
### map
@ -39,16 +59,8 @@ SampleSet.map2: (sampleSet, sampleSet, ((number, number) => number)) => sampleSe
SampleSet.map3: (sampleSet, sampleSet, sampleSet, ((number, number, number) => number)) => sampleSet
```
### toList
### mapN
```
SampleSet.toList: (sampleSet) => list<number>
```
Gets the internal samples of a sampleSet distribution. This is separate from the sampleN() function, which would shuffle the samples. toList() maintains order and length.
**Examples**
```
toList(toSampleSet(normal(5,2)))
SampleSet.mapN: (list<sampleSet>, (list<sampleSet> => number)) => sampleSet
```

View File

@ -0,0 +1,27 @@
---
sidebar_position: 6
title: Function
---
## declare (experimental)
Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making formal predictions. It allows you to limit the domain that your prediction will be used and scored within.
The one function that declarations currently have is that they impact plotting. If you `declare` a single-variable function within a specific range, this specific range will be plotted.
Declarations are currently experimental and will likely be removed or changed in the future.
```
Function.declare: (dict<{fn: lambda, inputs: array<dict<{min: number, max: number}>>}>) => declaration
```
**Examples**
```javascript
Function.declare({
fn: {|a| a+10 },
inputs: [
{min: 30, max: 100}
]
})
```

View File

@ -11,8 +11,6 @@ myList = [3, normal(5, 2), "random"];
### make
**Note: currently just called `makeList`, without the preix**
```
List.make: (number, 'a) => list<'a>
```
@ -37,9 +35,7 @@ toString: (list<'a>) => string
length: (list<'a>) => number
```
### up to
**Note: currently just called `upTo`, without the preix**
### upTo
```
List.upTo: (low:number, high:number) => list<number>

View File

@ -55,6 +55,12 @@ min: (list<number>) => number
mean: (list<number>) => number
```
### geometric mean
```
geomean: (list<number>) => number
```
### stdev
```
@ -117,6 +123,12 @@ product: (list<number>) => number
cumprod: (list<number>) => list<number>
```
### diff
```
diff: (list<number>) => list<number>
```
### subtract
```

View File

@ -17151,9 +17151,9 @@ terser-webpack-plugin@^5.0.3, terser-webpack-plugin@^5.1.3, terser-webpack-plugi
terser "^5.7.2"
terser@^4.1.2, terser@^4.6.3:
version "4.8.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==
version "4.8.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f"
integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==
dependencies:
commander "^2.20.0"
source-map "~0.6.1"