Merge pull request #1137 from quantified-uncertainty/develop
0.4.2 release
This commit is contained in:
commit
36f7f00fc3
20
.github/CODEOWNERS
vendored
20
.github/CODEOWNERS
vendored
|
@ -9,22 +9,22 @@
|
||||||
# This also holds true for GitHub teams.
|
# This also holds true for GitHub teams.
|
||||||
|
|
||||||
# Rescript
|
# Rescript
|
||||||
*.res @OAGr
|
*.res @berekuk @OAGr
|
||||||
*.resi @OAGr
|
*.resi @berekuk @OAGr
|
||||||
|
|
||||||
# Typescript
|
# Typescript
|
||||||
*.tsx @Hazelfire @OAGr
|
*.tsx @Hazelfire @berekuk @OAGr
|
||||||
*.ts @Hazelfire @OAGr
|
*.ts @Hazelfire @berekuk @OAGr
|
||||||
|
|
||||||
# Javascript
|
# Javascript
|
||||||
*.js @Hazelfire @OAGr
|
*.js @Hazelfire @berekuk @OAGr
|
||||||
|
|
||||||
# Any opsy files
|
# Any opsy files
|
||||||
.github/** @quinn-dougherty @OAGr
|
.github/** @quinn-doughert @berekuky @OAGr
|
||||||
*.json @quinn-dougherty @Hazelfire @OAGr
|
*.json @quinn-dougherty @Hazelfire @berekuk @OAGr
|
||||||
*.y*ml @quinn-dougherty @OAGr
|
*.y*ml @quinn-dougherty @berekuk @OAGr
|
||||||
*.config.js @Hazelfire @OAGr
|
*.config.js @Hazelfire @berekuk @OAGr
|
||||||
netlify.toml @quinn-dougherty @OAGr @Hazelfire
|
netlify.toml @quinn-dougherty @OAGr @berekuk @Hazelfire
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
*.md @quinn-dougherty @OAGr @Hazelfire
|
*.md @quinn-dougherty @OAGr @Hazelfire
|
||||||
|
|
250
.github/workflows/ci.yml
vendored
250
.github/workflows/ci.yml
vendored
|
@ -49,26 +49,26 @@ jobs:
|
||||||
with:
|
with:
|
||||||
paths: '["packages/cli/**"]'
|
paths: '["packages/cli/**"]'
|
||||||
|
|
||||||
# lang-lint:
|
lang-lint:
|
||||||
# name: Language lint
|
name: Language lint
|
||||||
# runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# needs: pre_check
|
needs: pre_check
|
||||||
# if: ${{ needs.pre_check.outputs.should_skip_lang != 'true' }}
|
if: ${{ needs.pre_check.outputs.should_skip_lang != 'true' }}
|
||||||
# defaults:
|
defaults:
|
||||||
# run:
|
run:
|
||||||
# shell: bash
|
shell: bash
|
||||||
# working-directory: packages/squiggle-lang
|
working-directory: packages/squiggle-lang
|
||||||
# steps:
|
steps:
|
||||||
# - uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
# - name: Install Dependencies
|
- name: Install Dependencies
|
||||||
# run: cd ../../ && yarn
|
run: cd ../../ && yarn
|
||||||
# - name: Check rescript lint
|
- name: Check rescript lint
|
||||||
# run: yarn lint:rescript
|
run: yarn lint:rescript
|
||||||
# - name: Check javascript, typescript, and markdown lint
|
- name: Check javascript, typescript, and markdown lint
|
||||||
# uses: creyD/prettier_action@v4.2
|
uses: creyD/prettier_action@v4.2
|
||||||
# with:
|
with:
|
||||||
# dry: true
|
dry: true
|
||||||
# prettier_options: --check packages/squiggle-lang
|
prettier_options: --check packages/squiggle-lang
|
||||||
|
|
||||||
lang-build-test-bundle:
|
lang-build-test-bundle:
|
||||||
name: Language build, test, and bundle
|
name: Language build, test, and bundle
|
||||||
|
@ -98,96 +98,96 @@ jobs:
|
||||||
- name: Upload typescript coverage report
|
- name: Upload typescript coverage report
|
||||||
run: yarn coverage:ts:ci
|
run: yarn coverage:ts:ci
|
||||||
|
|
||||||
# components-lint:
|
components-lint:
|
||||||
# name: Components lint
|
name: Components lint
|
||||||
# runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# needs: pre_check
|
needs: pre_check
|
||||||
# if: ${{ needs.pre_check.outputs.should_skip_components != 'true' }}
|
if: ${{ needs.pre_check.outputs.should_skip_components != 'true' }}
|
||||||
# defaults:
|
defaults:
|
||||||
# run:
|
run:
|
||||||
# shell: bash
|
shell: bash
|
||||||
# working-directory: packages/components
|
working-directory: packages/components
|
||||||
# steps:
|
steps:
|
||||||
# - uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
# - name: Check javascript, typescript, and markdown lint
|
- name: Check javascript, typescript, and markdown lint
|
||||||
# uses: creyD/prettier_action@v4.2
|
uses: creyD/prettier_action@v4.2
|
||||||
# with:
|
with:
|
||||||
# dry: true
|
dry: true
|
||||||
# prettier_options: --check packages/components --ignore-path packages/components/.prettierignore
|
prettier_options: --check packages/components --ignore-path packages/components/.prettierignore
|
||||||
#
|
|
||||||
# components-bundle-build:
|
|
||||||
# name: Components bundle and build
|
|
||||||
# runs-on: ubuntu-latest
|
|
||||||
# needs: pre_check
|
|
||||||
# if: ${{ (needs.pre_check.outputs.should_skip_components != 'true') || (needs.pre_check.outputs.should_skip_lang != 'true') }}
|
|
||||||
# defaults:
|
|
||||||
# run:
|
|
||||||
# shell: bash
|
|
||||||
# working-directory: packages/components
|
|
||||||
# steps:
|
|
||||||
# - uses: actions/checkout@v3
|
|
||||||
# - name: Install dependencies from monorepo level
|
|
||||||
# run: cd ../../ && yarn
|
|
||||||
# - name: Build rescript codebase in squiggle-lang
|
|
||||||
# run: cd ../squiggle-lang && yarn build
|
|
||||||
# - name: Run webpack
|
|
||||||
# run: yarn bundle
|
|
||||||
# - name: Build storybook
|
|
||||||
# run: yarn build
|
|
||||||
|
|
||||||
# website-lint:
|
components-bundle-build:
|
||||||
# name: Website lint
|
name: Components bundle and build
|
||||||
# runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# needs: pre_check
|
needs: pre_check
|
||||||
# if: ${{ needs.pre_check.outputs.should_skip_website != 'true' }}
|
if: ${{ (needs.pre_check.outputs.should_skip_components != 'true') || (needs.pre_check.outputs.should_skip_lang != 'true') }}
|
||||||
# defaults:
|
defaults:
|
||||||
# run:
|
run:
|
||||||
# shell: bash
|
shell: bash
|
||||||
# working-directory: packages/website
|
working-directory: packages/components
|
||||||
# steps:
|
steps:
|
||||||
# - uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
# - name: Check javascript, typescript, and markdown lint
|
- name: Install dependencies from monorepo level
|
||||||
# uses: creyD/prettier_action@v4.2
|
run: cd ../../ && yarn
|
||||||
# with:
|
- name: Build rescript codebase in squiggle-lang
|
||||||
# dry: true
|
run: cd ../squiggle-lang && yarn build
|
||||||
# prettier_options: --check packages/website
|
- name: Run webpack
|
||||||
#
|
run: yarn bundle
|
||||||
# website-build:
|
- name: Build storybook
|
||||||
# name: Website build
|
run: yarn build
|
||||||
# runs-on: ubuntu-latest
|
|
||||||
# needs: pre_check
|
website-lint:
|
||||||
# if: ${{ (needs.pre_check.outputs.should_skip_website != 'true') || (needs.pre_check.outputs.should_skip_lang != 'true') || (needs.pre_check.outputs.should_skip_components != 'true') }}
|
name: Website lint
|
||||||
# defaults:
|
runs-on: ubuntu-latest
|
||||||
# run:
|
needs: pre_check
|
||||||
# shell: bash
|
if: ${{ needs.pre_check.outputs.should_skip_website != 'true' }}
|
||||||
# working-directory: packages/website
|
defaults:
|
||||||
# steps:
|
run:
|
||||||
# - uses: actions/checkout@v3
|
shell: bash
|
||||||
# - name: Install dependencies from monorepo level
|
working-directory: packages/website
|
||||||
# run: cd ../../ && yarn
|
steps:
|
||||||
# - name: Build rescript in squiggle-lang
|
- uses: actions/checkout@v3
|
||||||
# run: cd ../squiggle-lang && yarn build
|
- name: Check javascript, typescript, and markdown lint
|
||||||
# - name: Build components
|
uses: creyD/prettier_action@v4.2
|
||||||
# run: cd ../components && yarn build
|
with:
|
||||||
# - name: Build website assets
|
dry: true
|
||||||
# run: yarn build
|
prettier_options: --check packages/website
|
||||||
#
|
|
||||||
# vscode-ext-lint:
|
website-build:
|
||||||
# name: VS Code extension lint
|
name: Website build
|
||||||
# runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# needs: pre_check
|
needs: pre_check
|
||||||
# if: ${{ needs.pre_check.outputs.should_skip_vscodeext != 'true' }}
|
if: ${{ (needs.pre_check.outputs.should_skip_website != 'true') || (needs.pre_check.outputs.should_skip_lang != 'true') || (needs.pre_check.outputs.should_skip_components != 'true') }}
|
||||||
# defaults:
|
defaults:
|
||||||
# run:
|
run:
|
||||||
# shell: bash
|
shell: bash
|
||||||
# working-directory: packages/vscode-ext
|
working-directory: packages/website
|
||||||
# steps:
|
steps:
|
||||||
# - uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
# - name: Check javascript, typescript, and markdown lint
|
- name: Install dependencies from monorepo level
|
||||||
# uses: creyD/prettier_action@v4.2
|
run: cd ../../ && yarn
|
||||||
# with:
|
- name: Build rescript in squiggle-lang
|
||||||
# dry: true
|
run: cd ../squiggle-lang && yarn build
|
||||||
# prettier_options: --check packages/vscode-ext
|
- name: Build components
|
||||||
|
run: cd ../components && yarn build
|
||||||
|
- name: Build website assets
|
||||||
|
run: yarn build
|
||||||
|
|
||||||
|
vscode-ext-lint:
|
||||||
|
name: VS Code extension lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: pre_check
|
||||||
|
if: ${{ needs.pre_check.outputs.should_skip_vscodeext != 'true' }}
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
working-directory: packages/vscode-ext
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Check javascript, typescript, and markdown lint
|
||||||
|
uses: creyD/prettier_action@v4.2
|
||||||
|
with:
|
||||||
|
dry: true
|
||||||
|
prettier_options: --check packages/vscode-ext
|
||||||
|
|
||||||
vscode-ext-build:
|
vscode-ext-build:
|
||||||
name: VS Code extension build
|
name: VS Code extension build
|
||||||
|
@ -204,19 +204,19 @@ jobs:
|
||||||
run: cd ../../ && yarn
|
run: cd ../../ && yarn
|
||||||
- name: Build
|
- name: Build
|
||||||
run: yarn compile
|
run: yarn compile
|
||||||
# cli-lint:
|
cli-lint:
|
||||||
# name: CLI lint
|
name: CLI lint
|
||||||
# runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# needs: pre_check
|
needs: pre_check
|
||||||
# if: ${{ needs.pre_check.outputs.should_skip_cli != 'true' }}
|
if: ${{ needs.pre_check.outputs.should_skip_cli != 'true' }}
|
||||||
# defaults:
|
defaults:
|
||||||
# run:
|
run:
|
||||||
# shell: bash
|
shell: bash
|
||||||
# working-directory: packages/cli
|
working-directory: packages/cli
|
||||||
# steps:
|
steps:
|
||||||
# - uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
# - name: Check javascript, typescript, and markdown lint
|
- name: Check javascript, typescript, and markdown lint
|
||||||
# uses: creyD/prettier_action@v4.2
|
uses: creyD/prettier_action@v4.2
|
||||||
# with:
|
with:
|
||||||
# dry: true
|
dry: true
|
||||||
# prettier_options: --check packages/cli
|
prettier_options: --check packages/cli
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -7,4 +7,7 @@ yarn-error.log
|
||||||
**/.sync.ffs_db
|
**/.sync.ffs_db
|
||||||
.direnv
|
.direnv
|
||||||
.log
|
.log
|
||||||
|
|
||||||
|
.vscode
|
||||||
|
todo.txt
|
||||||
result
|
result
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"packages/cli": "0.0.3",
|
"packages/cli": "0.0.3",
|
||||||
"packages/components": "0.3.1",
|
"packages/components": "0.4.1",
|
||||||
"packages/squiggle-lang": "0.3.0",
|
"packages/squiggle-lang": "0.4.1",
|
||||||
"packages/vscode-ext": "0.3.1",
|
"packages/vscode-ext": "0.4.1",
|
||||||
"packages/website": "0.3.0"
|
"packages/website": "0.0.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,7 @@ rec {
|
||||||
# custom gitignore so that the flake keeps build artefacts
|
# custom gitignore so that the flake keeps build artefacts
|
||||||
mv .gitignore GITIGNORE
|
mv .gitignore GITIGNORE
|
||||||
sed -i /Reducer_Peggy_GeneratedParser.js/d GITIGNORE
|
sed -i /Reducer_Peggy_GeneratedParser.js/d GITIGNORE
|
||||||
|
sed -i /ReducerProject_IncludeParser.js/d GITIGNORE
|
||||||
sed -i /\*.bs.js/d GITIGNORE
|
sed -i /\*.bs.js/d GITIGNORE
|
||||||
sed -i /\*.gen.ts/d GITIGNORE
|
sed -i /\*.gen.ts/d GITIGNORE
|
||||||
sed -i /\*.gen.tsx/d GITIGNORE
|
sed -i /\*.gen.tsx/d GITIGNORE
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
{
|
{
|
||||||
"name": "@quri/squiggle-components",
|
"name": "@quri/squiggle-components",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/react-dom": "^1.0.0",
|
"@floating-ui/react-dom": "^1.0.0",
|
||||||
"@floating-ui/react-dom-interactions": "^0.9.3",
|
"@floating-ui/react-dom-interactions": "^0.9.3",
|
||||||
"@headlessui/react": "^1.6.6",
|
"@headlessui/react": "^1.6.6",
|
||||||
"@heroicons/react": "^1.0.6",
|
"@heroicons/react": "^1.0.6",
|
||||||
"@hookform/resolvers": "^2.9.7",
|
"@hookform/resolvers": "^2.9.8",
|
||||||
"@quri/squiggle-lang": "^0.4.1",
|
"@quri/squiggle-lang": "^0.4.2",
|
||||||
"@react-hook/size": "^2.1.2",
|
"@react-hook/size": "^2.1.2",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"framer-motion": "^7.2.1",
|
"framer-motion": "^7.3.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-ace": "^10.1.0",
|
"react-ace": "^10.1.0",
|
||||||
"react-hook-form": "^7.34.2",
|
"react-hook-form": "^7.35.0",
|
||||||
"react-use": "^17.4.0",
|
"react-use": "^17.4.0",
|
||||||
"react-vega": "^7.6.0",
|
"react-vega": "^7.6.0",
|
||||||
"vega": "^5.22.1",
|
"vega": "^5.22.1",
|
||||||
|
@ -38,15 +38,15 @@
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^14.4.3",
|
"@testing-library/user-event": "^14.4.3",
|
||||||
"@types/jest": "^27.5.0",
|
"@types/jest": "^27.5.0",
|
||||||
"@types/lodash": "^4.14.184",
|
"@types/lodash": "^4.14.185",
|
||||||
"@types/node": "^18.7.15",
|
"@types/node": "^18.7.16",
|
||||||
"@types/react": "^18.0.18",
|
"@types/react": "^18.0.18",
|
||||||
"@types/styled-components": "^5.1.26",
|
"@types/styled-components": "^5.1.26",
|
||||||
"@types/webpack": "^5.28.0",
|
"@types/webpack": "^5.28.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"mini-css-extract-plugin": "^2.6.1",
|
"mini-css-extract-plugin": "^2.6.1",
|
||||||
"postcss-cli": "^10.0.0",
|
"postcss-cli": "^10.0.0",
|
||||||
"postcss-import": "^14.1.0",
|
"postcss-import": "^15.0.0",
|
||||||
"postcss-loader": "^7.0.1",
|
"postcss-loader": "^7.0.1",
|
||||||
"postcss-nesting": "^10.1.10",
|
"postcss-nesting": "^10.1.10",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
|
@ -55,11 +55,11 @@
|
||||||
"tailwindcss": "^3.1.8",
|
"tailwindcss": "^3.1.8",
|
||||||
"ts-loader": "^9.3.0",
|
"ts-loader": "^9.3.0",
|
||||||
"tsconfig-paths-webpack-plugin": "^4.0.0",
|
"tsconfig-paths-webpack-plugin": "^4.0.0",
|
||||||
"typescript": "^4.8.2",
|
"typescript": "^4.8.3",
|
||||||
"web-vitals": "^3.0.1",
|
"web-vitals": "^3.0.1",
|
||||||
"webpack": "^5.74.0",
|
"webpack": "^5.74.0",
|
||||||
"webpack-cli": "^4.10.0",
|
"webpack-cli": "^4.10.0",
|
||||||
"webpack-dev-server": "^4.10.0"
|
"webpack-dev-server": "^4.11.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.0 || ^17 || ^18",
|
"react": "^16.8.0 || ^17 || ^18",
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
resultMap,
|
resultMap,
|
||||||
SqRecord,
|
SqRecord,
|
||||||
environment,
|
environment,
|
||||||
|
SqDistributionTag,
|
||||||
} from "@quri/squiggle-lang";
|
} from "@quri/squiggle-lang";
|
||||||
import { Vega } from "react-vega";
|
import { Vega } from "react-vega";
|
||||||
import { ErrorAlert } from "./Alert";
|
import { ErrorAlert } from "./Alert";
|
||||||
|
@ -31,6 +32,7 @@ export type DistributionChartProps = {
|
||||||
environment: environment;
|
environment: environment;
|
||||||
width?: number;
|
width?: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
xAxisType?: "number" | "dateTime";
|
||||||
} & DistributionPlottingSettings;
|
} & DistributionPlottingSettings;
|
||||||
|
|
||||||
export function defaultPlot(distribution: SqDistribution): Plot {
|
export function defaultPlot(distribution: SqDistribution): Plot {
|
||||||
|
@ -56,14 +58,15 @@ export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
||||||
} = props;
|
} = props;
|
||||||
const [sized] = useSize((size) => {
|
const [sized] = useSize((size) => {
|
||||||
const shapes = flattenResult(
|
const shapes = flattenResult(
|
||||||
plot.distributions.map((x) => {
|
plot.distributions.map((x) =>
|
||||||
return resultMap(x.distribution.pointSet(environment), (pointSet) => ({
|
resultMap(x.distribution.pointSet(environment), (pointSet) => ({
|
||||||
...pointSet.asShape(),
|
|
||||||
name: x.name,
|
name: x.name,
|
||||||
// color: x.color, // not supported yet
|
// color: x.color, // not supported yet
|
||||||
}));
|
...pointSet.asShape(),
|
||||||
})
|
}))
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (shapes.tag === "Error") {
|
if (shapes.tag === "Error") {
|
||||||
return (
|
return (
|
||||||
<ErrorAlert heading="Distribution Error">
|
<ErrorAlert heading="Distribution Error">
|
||||||
|
@ -72,6 +75,14 @@ export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if this is a sample set, include the samples
|
||||||
|
const samples: number[] = [];
|
||||||
|
for (const { distribution } of plot?.distributions) {
|
||||||
|
if (distribution.tag === SqDistributionTag.SampleSet) {
|
||||||
|
samples.push(...distribution.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const spec = buildVegaSpec(props);
|
const spec = buildVegaSpec(props);
|
||||||
|
|
||||||
let widthProp = width ? width : size.width;
|
let widthProp = width ? width : size.width;
|
||||||
|
@ -94,7 +105,7 @@ export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
||||||
) : (
|
) : (
|
||||||
<Vega
|
<Vega
|
||||||
spec={spec}
|
spec={spec}
|
||||||
data={{ data: shapes.value, domain }}
|
data={{ data: shapes.value, domain, samples }}
|
||||||
width={widthProp - 10}
|
width={widthProp - 10}
|
||||||
height={height}
|
height={height}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
|
|
|
@ -48,6 +48,8 @@ export interface SquiggleChartProps {
|
||||||
minX?: number;
|
minX?: number;
|
||||||
/** Specify the upper bound of the x scale */
|
/** Specify the upper bound of the x scale */
|
||||||
maxX?: number;
|
maxX?: number;
|
||||||
|
/** Whether the x-axis should be dates or numbers */
|
||||||
|
xAxisType?: "number" | "dateTime";
|
||||||
/** Whether to show vega actions to the user, so they can copy the chart spec */
|
/** Whether to show vega actions to the user, so they can copy the chart spec */
|
||||||
distributionChartActions?: boolean;
|
distributionChartActions?: boolean;
|
||||||
enableLocalSettings?: boolean;
|
enableLocalSettings?: boolean;
|
||||||
|
@ -76,6 +78,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
|
||||||
maxX,
|
maxX,
|
||||||
color,
|
color,
|
||||||
title,
|
title,
|
||||||
|
xAxisType = "number",
|
||||||
distributionChartActions,
|
distributionChartActions,
|
||||||
enableLocalSettings = false,
|
enableLocalSettings = false,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -96,6 +99,7 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = React.memo(
|
||||||
maxX,
|
maxX,
|
||||||
color,
|
color,
|
||||||
title,
|
title,
|
||||||
|
xAxisType,
|
||||||
actions: distributionChartActions,
|
actions: distributionChartActions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { VisualizationSpec } from "react-vega";
|
import { VisualizationSpec } from "react-vega";
|
||||||
import type { LogScale, LinearScale, PowScale } from "vega";
|
import type { LogScale, LinearScale, PowScale, TimeScale } from "vega";
|
||||||
|
|
||||||
export type DistributionChartSpecOptions = {
|
export type DistributionChartSpecOptions = {
|
||||||
/** Set the x scale to be logarithmic by deault */
|
/** Set the x scale to be logarithmic by deault */
|
||||||
|
@ -14,9 +14,12 @@ export type DistributionChartSpecOptions = {
|
||||||
title?: string;
|
title?: string;
|
||||||
/** The formatting of the ticks */
|
/** The formatting of the ticks */
|
||||||
format?: string;
|
format?: string;
|
||||||
|
/** Whether the x-axis should be dates or numbers */
|
||||||
|
xAxisType?: "number" | "dateTime";
|
||||||
};
|
};
|
||||||
|
|
||||||
export let linearXScale: LinearScale = {
|
/** X Scales */
|
||||||
|
export const linearXScale: LinearScale = {
|
||||||
name: "xscale",
|
name: "xscale",
|
||||||
clamp: true,
|
clamp: true,
|
||||||
type: "linear",
|
type: "linear",
|
||||||
|
@ -25,15 +28,8 @@ export let linearXScale: LinearScale = {
|
||||||
nice: false,
|
nice: false,
|
||||||
domain: { data: "domain", field: "x" },
|
domain: { data: "domain", field: "x" },
|
||||||
};
|
};
|
||||||
export let linearYScale: LinearScale = {
|
|
||||||
name: "yscale",
|
|
||||||
type: "linear",
|
|
||||||
range: "height",
|
|
||||||
zero: true,
|
|
||||||
domain: { data: "domain", field: "y" },
|
|
||||||
};
|
|
||||||
|
|
||||||
export let logXScale: LogScale = {
|
export const logXScale: LogScale = {
|
||||||
name: "xscale",
|
name: "xscale",
|
||||||
type: "log",
|
type: "log",
|
||||||
range: "width",
|
range: "width",
|
||||||
|
@ -44,7 +40,25 @@ export let logXScale: LogScale = {
|
||||||
domain: { data: "domain", field: "x" },
|
domain: { data: "domain", field: "x" },
|
||||||
};
|
};
|
||||||
|
|
||||||
export let expYScale: PowScale = {
|
export const timeXScale: TimeScale = {
|
||||||
|
name: "xscale",
|
||||||
|
clamp: true,
|
||||||
|
type: "time",
|
||||||
|
range: "width",
|
||||||
|
nice: false,
|
||||||
|
domain: { data: "domain", field: "x" },
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Y Scales */
|
||||||
|
export const linearYScale: LinearScale = {
|
||||||
|
name: "yscale",
|
||||||
|
type: "linear",
|
||||||
|
range: "height",
|
||||||
|
zero: true,
|
||||||
|
domain: { data: "domain", field: "y" },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const expYScale: PowScale = {
|
||||||
name: "yscale",
|
name: "yscale",
|
||||||
type: "pow",
|
type: "pow",
|
||||||
exponent: 0.1,
|
exponent: 0.1,
|
||||||
|
@ -55,20 +69,25 @@ export let expYScale: PowScale = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defaultTickFormat = ".9~s";
|
export const defaultTickFormat = ".9~s";
|
||||||
|
export const timeTickFormat = "%b %d, %Y %H:%M";
|
||||||
|
const width = 500;
|
||||||
|
|
||||||
export function buildVegaSpec(
|
export function buildVegaSpec(
|
||||||
specOptions: DistributionChartSpecOptions
|
specOptions: DistributionChartSpecOptions
|
||||||
): VisualizationSpec {
|
): VisualizationSpec {
|
||||||
const {
|
const { title, minX, maxX, logX, expY, xAxisType = "number" } = specOptions;
|
||||||
format = defaultTickFormat,
|
|
||||||
title,
|
const dateTime = xAxisType === "dateTime";
|
||||||
minX,
|
|
||||||
maxX,
|
// some fallbacks
|
||||||
logX,
|
const format = specOptions?.format
|
||||||
expY,
|
? specOptions.format
|
||||||
} = specOptions;
|
: dateTime
|
||||||
|
? timeTickFormat
|
||||||
|
: defaultTickFormat;
|
||||||
|
|
||||||
|
let xScale = dateTime ? timeXScale : logX ? logXScale : linearXScale;
|
||||||
|
|
||||||
let xScale = logX ? logXScale : linearXScale;
|
|
||||||
if (minX !== undefined && Number.isFinite(minX)) {
|
if (minX !== undefined && Number.isFinite(minX)) {
|
||||||
xScale = { ...xScale, domainMin: minX };
|
xScale = { ...xScale, domainMin: minX };
|
||||||
}
|
}
|
||||||
|
@ -77,21 +96,36 @@ export function buildVegaSpec(
|
||||||
xScale = { ...xScale, domainMax: maxX };
|
xScale = { ...xScale, domainMax: maxX };
|
||||||
}
|
}
|
||||||
|
|
||||||
let spec: VisualizationSpec = {
|
const spec: VisualizationSpec = {
|
||||||
$schema: "https://vega.github.io/schema/vega/v5.json",
|
$schema: "https://vega.github.io/schema/vega/v5.json",
|
||||||
description: "Squiggle plot chart",
|
description: "Squiggle plot chart",
|
||||||
width: 500,
|
width: width,
|
||||||
height: 100,
|
height: 100,
|
||||||
padding: 5,
|
padding: 5,
|
||||||
data: [
|
data: [{ name: "data" }, { name: "domain" }, { name: "samples" }],
|
||||||
|
signals: [
|
||||||
{
|
{
|
||||||
name: "data",
|
name: "hover",
|
||||||
|
value: null,
|
||||||
|
on: [
|
||||||
|
{ events: "mouseover", update: "datum" },
|
||||||
|
{ events: "mouseout", update: "null" },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "domain",
|
name: "position",
|
||||||
|
value: "[0, 0]",
|
||||||
|
on: [
|
||||||
|
{ events: "mousemove", update: "xy() " },
|
||||||
|
{ events: "mouseout", update: "null" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "position_scaled",
|
||||||
|
value: null,
|
||||||
|
update: "isArray(position) ? invert('xscale', position[0]) : ''",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
signals: [],
|
|
||||||
scales: [
|
scales: [
|
||||||
xScale,
|
xScale,
|
||||||
expY ? expYScale : linearYScale,
|
expY ? expYScale : linearYScale,
|
||||||
|
@ -115,7 +149,7 @@ export function buildVegaSpec(
|
||||||
domainColor: "#fff",
|
domainColor: "#fff",
|
||||||
domainOpacity: 0.0,
|
domainOpacity: 0.0,
|
||||||
format: format,
|
format: format,
|
||||||
tickCount: 10,
|
tickCount: dateTime ? 3 : 10,
|
||||||
labelOverlap: "greedy",
|
labelOverlap: "greedy",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -232,13 +266,16 @@ export function buildVegaSpec(
|
||||||
},
|
},
|
||||||
size: [{ value: 100 }],
|
size: [{ value: 100 }],
|
||||||
tooltip: {
|
tooltip: {
|
||||||
signal: "{ probability: datum.y, value: datum.x }",
|
signal: dateTime
|
||||||
|
? "{ probability: datum.y, value: datetime(datum.x) }"
|
||||||
|
: "{ probability: datum.y, value: datum.x }",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
x: {
|
x: {
|
||||||
scale: "xscale",
|
scale: "xscale",
|
||||||
field: "x",
|
field: "x",
|
||||||
|
offset: 0.5, // if this is not included, the circles are slightly left of center.
|
||||||
},
|
},
|
||||||
y: {
|
y: {
|
||||||
scale: "yscale",
|
scale: "yscale",
|
||||||
|
@ -255,6 +292,69 @@ export function buildVegaSpec(
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "sampleset",
|
||||||
|
type: "rect",
|
||||||
|
from: { data: "samples" },
|
||||||
|
encode: {
|
||||||
|
enter: {
|
||||||
|
x: { scale: "xscale", field: "data" },
|
||||||
|
width: { value: 0.1 },
|
||||||
|
|
||||||
|
y: { value: 25, offset: { signal: "height" } },
|
||||||
|
height: { value: 5 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
name: "announcer",
|
||||||
|
interactive: false,
|
||||||
|
encode: {
|
||||||
|
enter: {
|
||||||
|
x: { signal: String(width), offset: 1 }, // vega would prefer its internal ` "width" ` variable, but that breaks the squiggle playground. Just setting it to the same var as used elsewhere in the spec achieves the same result.
|
||||||
|
fill: { value: "black" },
|
||||||
|
fontSize: { value: 20 },
|
||||||
|
align: { value: "right" },
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
text: {
|
||||||
|
signal: dateTime
|
||||||
|
? "position_scaled ? utcyear(position_scaled) + '-' + utcmonth(position_scaled) + '-' + utcdate(position_scaled) + 'T' + utchours(position_scaled)+':' +utcminutes(position_scaled) : ''"
|
||||||
|
: "position_scaled ? format(position_scaled, ',.4r') : ''",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "rule",
|
||||||
|
interactive: false,
|
||||||
|
encode: {
|
||||||
|
enter: {
|
||||||
|
x: { value: 0 },
|
||||||
|
y: { scale: "yscale", value: 0 },
|
||||||
|
|
||||||
|
y2: {
|
||||||
|
signal: "height",
|
||||||
|
offset: 2,
|
||||||
|
},
|
||||||
|
strokeDash: { value: [5, 5] },
|
||||||
|
},
|
||||||
|
|
||||||
|
update: {
|
||||||
|
x: {
|
||||||
|
signal:
|
||||||
|
"position ? position[0] < 0 ? null : position[0] > width ? null : position[0]: null",
|
||||||
|
},
|
||||||
|
|
||||||
|
opacity: {
|
||||||
|
signal:
|
||||||
|
"position ? position[0] < 0 ? 0 : position[0] > width ? 0 : 1 : 0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
legends: [
|
legends: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -79,6 +79,22 @@ could be continuous, discrete or mixed.
|
||||||
</Story>
|
</Story>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
|
### Date Distribution
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story
|
||||||
|
name="Date Distribution"
|
||||||
|
args={{
|
||||||
|
code: "mx(1661819770311, 1661829770311, 1661839770311)",
|
||||||
|
width,
|
||||||
|
xAxisType: "dateTime",
|
||||||
|
width,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Template.bind({})}
|
||||||
|
</Story>
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
## Mixed distributions
|
## Mixed distributions
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
|
|
1
packages/squiggle-lang/.gitignore
vendored
1
packages/squiggle-lang/.gitignore
vendored
|
@ -23,3 +23,4 @@ coverage
|
||||||
.nyc_output/
|
.nyc_output/
|
||||||
src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.js
|
src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.js
|
||||||
src/rescript/Reducer/Reducer_Peggy/helpers.js
|
src/rescript/Reducer/Reducer_Peggy/helpers.js
|
||||||
|
src/rescript/ReducerProject/ReducerProject_IncludeParser.js
|
||||||
|
|
|
@ -19,7 +19,7 @@ let testMacro_ = (
|
||||||
let bindings = Bindings.fromArray(bindArray)
|
let bindings = Bindings.fromArray(bindArray)
|
||||||
tester(expr->T.toString, () =>
|
tester(expr->T.toString, () =>
|
||||||
expr
|
expr
|
||||||
->Macro.expandMacroCall(
|
->Macro.expandMacroCallRs(
|
||||||
bindings,
|
bindings,
|
||||||
ProjectAccessorsT.identityAccessors,
|
ProjectAccessorsT.identityAccessors,
|
||||||
Expression.reduceExpressionInProject,
|
Expression.reduceExpressionInProject,
|
||||||
|
@ -44,6 +44,7 @@ let testMacroEval_ = (
|
||||||
ProjectAccessorsT.identityAccessors,
|
ProjectAccessorsT.identityAccessors,
|
||||||
Expression.reduceExpressionInProject,
|
Expression.reduceExpressionInProject,
|
||||||
)
|
)
|
||||||
|
->Ok
|
||||||
->InternalExpressionValue.toStringResult
|
->InternalExpressionValue.toStringResult
|
||||||
->expect
|
->expect
|
||||||
->toEqual(expectedValue)
|
->toEqual(expectedValue)
|
||||||
|
|
|
@ -16,7 +16,7 @@ let checkArgumentsSourceCode = (aTypeSourceCode: string, sourceCode: string): re
|
||||||
> => {
|
> => {
|
||||||
let reducerFn = Expression.reduceExpressionInProject
|
let reducerFn = Expression.reduceExpressionInProject
|
||||||
let rResult =
|
let rResult =
|
||||||
Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
Expression.BackCompatible.parse(sourceCode)->Belt.Result.map(expr =>
|
||||||
reducerFn(expr, Bindings.emptyBindings, ProjectAccessorsT.identityAccessors)
|
reducerFn(expr, Bindings.emptyBindings, ProjectAccessorsT.identityAccessors)
|
||||||
)
|
)
|
||||||
rResult->Belt.Result.flatMap(result =>
|
rResult->Belt.Result.flatMap(result =>
|
||||||
|
|
|
@ -19,7 +19,7 @@ let isTypeOfSourceCode = (aTypeSourceCode: string, sourceCode: string): result<
|
||||||
> => {
|
> => {
|
||||||
let reducerFn = Expression.reduceExpressionInProject
|
let reducerFn = Expression.reduceExpressionInProject
|
||||||
let rResult =
|
let rResult =
|
||||||
Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
Expression.BackCompatible.parse(sourceCode)->Belt.Result.map(expr =>
|
||||||
reducerFn(expr, Bindings.emptyBindings, ProjectAccessorsT.identityAccessors)
|
reducerFn(expr, Bindings.emptyBindings, ProjectAccessorsT.identityAccessors)
|
||||||
)
|
)
|
||||||
rResult->Belt.Result.flatMap(result => TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn))
|
rResult->Belt.Result.flatMap(result => TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn))
|
||||||
|
|
|
@ -56,7 +56,7 @@ describe("test exceptions", () => {
|
||||||
testDescriptionEvalToBe(
|
testDescriptionEvalToBe(
|
||||||
"javascript exception",
|
"javascript exception",
|
||||||
"javascriptraise('div by 0')",
|
"javascriptraise('div by 0')",
|
||||||
"Error(JS Exception: Error: 'div by 0')",
|
"Error(Error: 'div by 0')",
|
||||||
)
|
)
|
||||||
// testDescriptionEvalToBe(
|
// testDescriptionEvalToBe(
|
||||||
// "rescript exception",
|
// "rescript exception",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@quri/squiggle-lang",
|
"name": "@quri/squiggle-lang",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"homepage": "https://squiggle-language.com",
|
"homepage": "https://squiggle-language.com",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
"@stdlib/stats": "^0.0.13",
|
"@stdlib/stats": "^0.0.13",
|
||||||
"jstat": "^1.9.5",
|
"jstat": "^1.9.5",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mathjs": "^11.1.0",
|
"mathjs": "^11.2.0",
|
||||||
"pdfast": "^0.2.0"
|
"pdfast": "^0.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
"bisect_ppx": "^2.7.1",
|
"bisect_ppx": "^2.7.1",
|
||||||
"chalk": "^5.0.1",
|
"chalk": "^5.0.1",
|
||||||
"codecov": "^3.8.3",
|
"codecov": "^3.8.3",
|
||||||
"fast-check": "^3.1.2",
|
"fast-check": "^3.1.3",
|
||||||
"gentype": "^4.5.0",
|
"gentype": "^4.5.0",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"moduleserve": "^0.9.1",
|
"moduleserve": "^0.9.1",
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
"ts-jest": "^27.1.4",
|
"ts-jest": "^27.1.4",
|
||||||
"ts-loader": "^9.3.0",
|
"ts-loader": "^9.3.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^4.8.2",
|
"typescript": "^4.8.3",
|
||||||
"webpack": "^5.74.0",
|
"webpack": "^5.74.0",
|
||||||
"webpack-cli": "^4.10.0"
|
"webpack-cli": "^4.10.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -80,27 +80,28 @@ abstract class SqAbstractDistribution {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SqPointSetDistribution extends SqAbstractDistribution {
|
export class SqPointSetDistribution extends SqAbstractDistribution {
|
||||||
tag = Tag.PointSet;
|
tag = Tag.PointSet as const;
|
||||||
|
|
||||||
value() {
|
value() {
|
||||||
return this.valueMethod(RSDistribution.getPointSet);
|
return wrapPointSetDist(this.valueMethod(RSDistribution.getPointSet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SqSampleSetDistribution extends SqAbstractDistribution {
|
export class SqSampleSetDistribution extends SqAbstractDistribution {
|
||||||
tag = Tag.SampleSet;
|
tag = Tag.SampleSet as const;
|
||||||
|
|
||||||
value() {
|
value(): number[] {
|
||||||
return this.valueMethod(RSDistribution.getSampleSet);
|
return this.valueMethod(RSDistribution.getSampleSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SqSymbolicDistribution extends SqAbstractDistribution {
|
export class SqSymbolicDistribution extends SqAbstractDistribution {
|
||||||
tag = Tag.Symbolic;
|
tag = Tag.Symbolic as const;
|
||||||
|
|
||||||
value() {
|
// not wrapped for TypeScript yet
|
||||||
return this.valueMethod(RSDistribution.getSymbolic);
|
// value() {
|
||||||
}
|
// return this.valueMethod(RSDistribution.getSymbolic);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagToClass = {
|
const tagToClass = {
|
||||||
|
|
|
@ -62,6 +62,7 @@ let toPointSetDist = (
|
||||||
~samplingInputs: SamplingInputs.samplingInputs,
|
~samplingInputs: SamplingInputs.samplingInputs,
|
||||||
(),
|
(),
|
||||||
): Internals.Types.outputs => {
|
): Internals.Types.outputs => {
|
||||||
|
let samples = Js.Array2.copy(samples)
|
||||||
Array.fast_sort(compare, samples)
|
Array.fast_sort(compare, samples)
|
||||||
let minDiscreteToKeep = MagicNumbers.ToPointSet.minDiscreteToKeep(samples)
|
let minDiscreteToKeep = MagicNumbers.ToPointSet.minDiscreteToKeep(samples)
|
||||||
let (continuousPart, discretePart) = E.A.Floats.Sorted.splitContinuousAndDiscreteForMinWeight(
|
let (continuousPart, discretePart) = E.A.Floats.Sorted.splitContinuousAndDiscreteForMinWeight(
|
||||||
|
|
|
@ -74,12 +74,11 @@ module Integration = {
|
||||||
reducer,
|
reducer,
|
||||||
)
|
)
|
||||||
let result = switch resultAsInternalExpression {
|
let result = switch resultAsInternalExpression {
|
||||||
| Ok(IEvNumber(x)) => Ok(x)
|
| IEvNumber(x) => Ok(x)
|
||||||
| Error(_) =>
|
| _ =>
|
||||||
Error(
|
Error(
|
||||||
"Error 1 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead",
|
"Error 1 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead",
|
||||||
)
|
)
|
||||||
| _ => Error("Error 2 in Danger.integrate")
|
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -143,7 +142,7 @@ module Integration = {
|
||||||
}
|
}
|
||||||
| Error(b) =>
|
| Error(b) =>
|
||||||
Error(
|
Error(
|
||||||
"Integration error 3 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead." ++
|
"Integration error 2 in Danger.integrate. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead." ++
|
||||||
"Original error: " ++
|
"Original error: " ++
|
||||||
b,
|
b,
|
||||||
)
|
)
|
||||||
|
@ -309,14 +308,10 @@ module DiminishingReturns = {
|
||||||
reducer,
|
reducer,
|
||||||
)
|
)
|
||||||
switch resultAsInternalExpression {
|
switch resultAsInternalExpression {
|
||||||
| Ok(IEvNumber(x)) => Ok(x)
|
| IEvNumber(x) => Ok(x)
|
||||||
| Error(_) =>
|
|
||||||
Error(
|
|
||||||
"Error 1 in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead",
|
|
||||||
)
|
|
||||||
| _ =>
|
| _ =>
|
||||||
Error(
|
Error(
|
||||||
"Error 2 in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions",
|
"Error 1 in Danger.optimalAllocationGivenDiminishingMarginalReturnsForManyFunctions. It's possible that your function doesn't return a number, try definining auxiliaryFunction(x) = mean(yourFunction(x)) and integrate auxiliaryFunction instead",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,19 +32,15 @@ module Internals = {
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
eLambdaValue,
|
eLambdaValue,
|
||||||
reducer: ProjectReducerFnT.t,
|
reducer: ProjectReducerFnT.t,
|
||||||
): result<ReducerInterface_InternalExpressionValue.t, Reducer_ErrorValue.errorValue> => {
|
): ReducerInterface_InternalExpressionValue.t => {
|
||||||
let rMappedList = array->E.A.reduceReverse(Ok(list{}), (rAcc, elem) =>
|
Belt.Array.map(array, elem =>
|
||||||
rAcc->E.R.bind(_, acc => {
|
Reducer_Expression_Lambda.doLambdaCall(
|
||||||
let rNewElem = Reducer_Expression_Lambda.doLambdaCall(
|
|
||||||
eLambdaValue,
|
eLambdaValue,
|
||||||
list{elem},
|
list{elem},
|
||||||
(accessors: ProjectAccessorsT.t),
|
(accessors: ProjectAccessorsT.t),
|
||||||
(reducer: ProjectReducerFnT.t),
|
(reducer: ProjectReducerFnT.t),
|
||||||
)
|
)
|
||||||
rNewElem->E.R2.fmap(newElem => list{newElem, ...acc})
|
)->Wrappers.evArray
|
||||||
})
|
|
||||||
)
|
|
||||||
rMappedList->E.R2.fmap(mappedList => mappedList->Belt.List.toArray->Wrappers.evArray)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let reduce = (
|
let reduce = (
|
||||||
|
@ -54,11 +50,9 @@ module Internals = {
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: ProjectReducerFnT.t,
|
reducer: ProjectReducerFnT.t,
|
||||||
) => {
|
) => {
|
||||||
aValueArray->E.A.reduce(Ok(initialValue), (rAcc, elem) =>
|
aValueArray->E.A.reduce(initialValue, (acc, elem) =>
|
||||||
rAcc->E.R.bind(_, acc =>
|
|
||||||
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, accessors, reducer)
|
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, accessors, reducer)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let reduceReverse = (
|
let reduceReverse = (
|
||||||
|
@ -68,11 +62,9 @@ module Internals = {
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: ProjectReducerFnT.t,
|
reducer: ProjectReducerFnT.t,
|
||||||
) => {
|
) => {
|
||||||
aValueArray->Belt.Array.reduceReverse(Ok(initialValue), (rAcc, elem) =>
|
aValueArray->Belt.Array.reduceReverse(initialValue, (acc, elem) =>
|
||||||
rAcc->Belt.Result.flatMap(acc =>
|
|
||||||
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, accessors, reducer)
|
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, accessors, reducer)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let filter = (
|
let filter = (
|
||||||
|
@ -81,25 +73,18 @@ module Internals = {
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: ProjectReducerFnT.t,
|
reducer: ProjectReducerFnT.t,
|
||||||
) => {
|
) => {
|
||||||
let rMappedList = aValueArray->Belt.Array.reduceReverse(Ok(list{}), (rAcc, elem) =>
|
Js.Array2.filter(aValueArray, elem => {
|
||||||
rAcc->E.R.bind(_, acc => {
|
let result = Reducer_Expression_Lambda.doLambdaCall(
|
||||||
let rNewElem = Reducer_Expression_Lambda.doLambdaCall(
|
|
||||||
aLambdaValue,
|
aLambdaValue,
|
||||||
list{elem},
|
list{elem},
|
||||||
accessors,
|
accessors,
|
||||||
reducer,
|
reducer,
|
||||||
)
|
)
|
||||||
rNewElem->E.R2.fmap(newElem => {
|
switch result {
|
||||||
switch newElem {
|
| IEvBool(true) => true
|
||||||
| IEvBool(true) => list{elem, ...acc}
|
| _ => false
|
||||||
| _ => acc
|
|
||||||
}
|
}
|
||||||
})
|
})->Wrappers.evArray
|
||||||
})
|
|
||||||
)
|
|
||||||
let result =
|
|
||||||
rMappedList->E.R2.fmap(mappedList => mappedList->Belt.List.toArray->Wrappers.evArray)
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +201,7 @@ let library = [
|
||||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvArray(array), IEvLambda(lambda)] =>
|
| [IEvArray(array), IEvLambda(lambda)] =>
|
||||||
Internals.map(array, accessors, lambda, reducer)->E.R2.errMap(_ => "Error!")
|
Ok(Internals.map(array, accessors, lambda, reducer))
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
@ -236,9 +221,7 @@ let library = [
|
||||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
|
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
|
||||||
Internals.reduce(array, initialValue, lambda, accessors, reducer)->E.R2.errMap(_ =>
|
Ok(Internals.reduce(array, initialValue, lambda, accessors, reducer))
|
||||||
"Error!"
|
|
||||||
)
|
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
@ -258,13 +241,7 @@ let library = [
|
||||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
|
| [IEvArray(array), initialValue, IEvLambda(lambda)] =>
|
||||||
Internals.reduceReverse(
|
Ok(Internals.reduceReverse(array, initialValue, lambda, accessors, reducer))
|
||||||
array,
|
|
||||||
initialValue,
|
|
||||||
lambda,
|
|
||||||
accessors,
|
|
||||||
reducer,
|
|
||||||
)->E.R2.errMap(_ => "Error!")
|
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
@ -284,7 +261,7 @@ let library = [
|
||||||
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) =>
|
~run=(inputs, _, accessors: ProjectAccessorsT.t, reducer: ProjectReducerFnT.t) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvArray(array), IEvLambda(lambda)] =>
|
| [IEvArray(array), IEvLambda(lambda)] =>
|
||||||
Internals.filter(array, lambda, accessors, reducer)->E.R2.errMap(_ => "Error!")
|
Ok(Internals.filter(array, lambda, accessors, reducer))
|
||||||
| _ => Error(impossibleError)
|
| _ => Error(impossibleError)
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
|
|
@ -37,7 +37,7 @@ module Internal = {
|
||||||
|
|
||||||
let doLambdaCall = (aLambdaValue, list, environment, reducer) =>
|
let doLambdaCall = (aLambdaValue, list, environment, reducer) =>
|
||||||
switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, environment, reducer) {
|
switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, environment, reducer) {
|
||||||
| Ok(IEvNumber(f)) => Ok(f)
|
| IEvNumber(f) => Ok(f)
|
||||||
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ module Internal = {
|
||||||
reducer: ProjectReducerFnT.t,
|
reducer: ProjectReducerFnT.t,
|
||||||
) =>
|
) =>
|
||||||
switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, accessors, reducer) {
|
switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, accessors, reducer) {
|
||||||
| Ok(IEvNumber(f)) => Ok(f)
|
| IEvNumber(f) => Ok(f)
|
||||||
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ module BindingsReplacer = Reducer_Expression_BindingsReplacer
|
||||||
module Continuation = ReducerInterface_Value_Continuation
|
module Continuation = ReducerInterface_Value_Continuation
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module ExternalLibrary = ReducerInterface.ExternalLibrary
|
module ExternalLibrary = ReducerInterface.ExternalLibrary
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module Lambda = Reducer_Expression_Lambda
|
module Lambda = Reducer_Expression_Lambda
|
||||||
module MathJs = Reducer_MathJs
|
module MathJs = Reducer_MathJs
|
||||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
@ -111,7 +112,7 @@ let callInternal = (
|
||||||
module SampleMap = {
|
module SampleMap = {
|
||||||
let doLambdaCall = (aLambdaValue, list) =>
|
let doLambdaCall = (aLambdaValue, list) =>
|
||||||
switch Lambda.doLambdaCall(aLambdaValue, list, accessors, reducer) {
|
switch Lambda.doLambdaCall(aLambdaValue, list, accessors, reducer) {
|
||||||
| Ok(IEvNumber(f)) => Ok(f)
|
| IEvNumber(f) => Ok(f)
|
||||||
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,13 +202,17 @@ let dispatch = (
|
||||||
call: functionCall,
|
call: functionCall,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: ProjectReducerFnT.t,
|
reducer: ProjectReducerFnT.t,
|
||||||
): result<internalExpressionValue, errorValue> =>
|
): internalExpressionValue =>
|
||||||
try {
|
try {
|
||||||
let (fn, args) = call
|
let (fn, args) = call
|
||||||
// There is a bug that prevents string match in patterns
|
// There is a bug that prevents string match in patterns
|
||||||
// So we have to recreate a copy of the string
|
// So we have to recreate a copy of the string
|
||||||
ExternalLibrary.dispatch((Js.String.make(fn), args), accessors, reducer, callInternal)
|
ExternalLibrary.dispatch(
|
||||||
|
(Js.String.make(fn), args),
|
||||||
|
accessors,
|
||||||
|
reducer,
|
||||||
|
callInternal,
|
||||||
|
)->InternalExpressionValue.resultToValue
|
||||||
} catch {
|
} catch {
|
||||||
| Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error
|
| exn => Reducer_ErrorValue.fromException(exn)->Reducer_ErrorValue.toException
|
||||||
| _ => RETodo("unhandled rescript exception")->Error
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,9 @@ module ExpressionWithContext = Reducer_ExpressionWithContext
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
module ProjectReducerFnT = ReducerProject_ReducerFn_T
|
||||||
module Result = Belt.Result
|
|
||||||
|
|
||||||
open Reducer_Expression_ExpressionBuilder
|
open Reducer_Expression_ExpressionBuilder
|
||||||
|
|
||||||
type errorValue = ErrorValue.errorValue
|
|
||||||
type expression = ExpressionT.expression
|
type expression = ExpressionT.expression
|
||||||
type expressionWithContext = ExpressionWithContext.expressionWithContext
|
type expressionWithContext = ExpressionWithContext.expressionWithContext
|
||||||
|
|
||||||
|
@ -25,21 +23,15 @@ let dispatchMacroCall = (
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
reduceExpression: ProjectReducerFnT.t,
|
reduceExpression: ProjectReducerFnT.t,
|
||||||
): result<expressionWithContext, errorValue> => {
|
): expressionWithContext => {
|
||||||
let useExpressionToSetBindings = (bindingExpr: expression, accessors, statement, newCode) => {
|
let useExpressionToSetBindings = (bindingExpr: expression, accessors, statement, newCode) => {
|
||||||
let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, accessors)
|
let nameSpaceValue = reduceExpression(bindingExpr, bindings, accessors)
|
||||||
|
|
||||||
rExternalBindingsValue->Result.flatMap(nameSpaceValue => {
|
|
||||||
let newBindings = Bindings.fromExpressionValue(nameSpaceValue)
|
let newBindings = Bindings.fromExpressionValue(nameSpaceValue)
|
||||||
|
|
||||||
let rNewStatement = BindingsReplacer.replaceSymbols(newBindings, statement)
|
let boundStatement = BindingsReplacer.replaceSymbols(newBindings, statement)
|
||||||
rNewStatement->Result.map(boundStatement =>
|
|
||||||
ExpressionWithContext.withContext(
|
ExpressionWithContext.withContext(newCode(newBindings->eModule, boundStatement), newBindings)
|
||||||
newCode(newBindings->eModule, boundStatement),
|
|
||||||
newBindings,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let correspondingSetBindingsFn = (fnName: string): string =>
|
let correspondingSetBindingsFn = (fnName: string): string =>
|
||||||
|
@ -52,7 +44,7 @@ let dispatchMacroCall = (
|
||||||
}
|
}
|
||||||
|
|
||||||
let doBindStatement = (bindingExpr: expression, statement: expression, accessors) => {
|
let doBindStatement = (bindingExpr: expression, statement: expression, accessors) => {
|
||||||
let defaultStatement = ErrorValue.REAssignmentExpected->Error
|
let defaultStatement = ErrorValue.REAssignmentExpected
|
||||||
switch statement {
|
switch statement {
|
||||||
| ExpressionT.EList(list{ExpressionT.EValue(IEvCall(callName)), symbolExpr, statement}) => {
|
| ExpressionT.EList(list{ExpressionT.EValue(IEvCall(callName)), symbolExpr, statement}) => {
|
||||||
let setBindingsFn = correspondingSetBindingsFn(callName)
|
let setBindingsFn = correspondingSetBindingsFn(callName)
|
||||||
|
@ -62,17 +54,18 @@ let dispatchMacroCall = (
|
||||||
boundStatement,
|
boundStatement,
|
||||||
) => eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement}))
|
) => eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement}))
|
||||||
} else {
|
} else {
|
||||||
defaultStatement
|
defaultStatement->Reducer_ErrorValue.toException
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| _ => defaultStatement
|
| _ => defaultStatement->Reducer_ErrorValue.toException
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let doBindExpression = (bindingExpr: expression, statement: expression, accessors): result<
|
let doBindExpression = (
|
||||||
expressionWithContext,
|
bindingExpr: expression,
|
||||||
errorValue,
|
statement: expression,
|
||||||
> => {
|
accessors,
|
||||||
|
): expressionWithContext => {
|
||||||
let defaultStatement = () =>
|
let defaultStatement = () =>
|
||||||
useExpressionToSetBindings(bindingExpr, accessors, statement, (
|
useExpressionToSetBindings(bindingExpr, accessors, statement, (
|
||||||
_newBindingsExpr,
|
_newBindingsExpr,
|
||||||
|
@ -100,10 +93,11 @@ let dispatchMacroCall = (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let doBlock = (exprs: list<expression>, _bindings: ExpressionT.bindings, _accessors): result<
|
let doBlock = (
|
||||||
expressionWithContext,
|
exprs: list<expression>,
|
||||||
errorValue,
|
_bindings: ExpressionT.bindings,
|
||||||
> => {
|
_accessors,
|
||||||
|
): expressionWithContext => {
|
||||||
let exprsArray = Belt.List.toArray(exprs)
|
let exprsArray = Belt.List.toArray(exprs)
|
||||||
let maxIndex = Js.Array2.length(exprsArray) - 1
|
let maxIndex = Js.Array2.length(exprsArray) - 1
|
||||||
let newStatement = exprsArray->Js.Array2.reducei((acc, statement, index) =>
|
let newStatement = exprsArray->Js.Array2.reducei((acc, statement, index) =>
|
||||||
|
@ -119,14 +113,14 @@ let dispatchMacroCall = (
|
||||||
eBindStatement(acc, statement)
|
eBindStatement(acc, statement)
|
||||||
}
|
}
|
||||||
, eSymbol("undefined block"))
|
, eSymbol("undefined block"))
|
||||||
ExpressionWithContext.noContext(newStatement)->Ok
|
ExpressionWithContext.noContext(newStatement)
|
||||||
}
|
}
|
||||||
|
|
||||||
let doLambdaDefinition = (
|
let doLambdaDefinition = (
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
parameters: array<string>,
|
parameters: array<string>,
|
||||||
lambdaDefinition: ExpressionT.expression,
|
lambdaDefinition: ExpressionT.expression,
|
||||||
) => ExpressionWithContext.noContext(eLambda(parameters, bindings, lambdaDefinition))->Ok
|
) => ExpressionWithContext.noContext(eLambda(parameters, bindings, lambdaDefinition))
|
||||||
|
|
||||||
let doTernary = (
|
let doTernary = (
|
||||||
condition: expression,
|
condition: expression,
|
||||||
|
@ -134,28 +128,28 @@ let dispatchMacroCall = (
|
||||||
ifFalse: expression,
|
ifFalse: expression,
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
accessors,
|
accessors,
|
||||||
): result<expressionWithContext, errorValue> => {
|
): expressionWithContext => {
|
||||||
let blockCondition = ExpressionBuilder.eBlock(list{condition})
|
let blockCondition = ExpressionBuilder.eBlock(list{condition})
|
||||||
let rCondition = reduceExpression(blockCondition, bindings, accessors)
|
let conditionValue = reduceExpression(blockCondition, bindings, accessors)
|
||||||
rCondition->Result.flatMap(conditionValue =>
|
|
||||||
switch conditionValue {
|
switch conditionValue {
|
||||||
| InternalExpressionValue.IEvBool(false) => {
|
| InternalExpressionValue.IEvBool(false) => {
|
||||||
let ifFalseBlock = eBlock(list{ifFalse})
|
let ifFalseBlock = eBlock(list{ifFalse})
|
||||||
ExpressionWithContext.withContext(ifFalseBlock, bindings)->Ok
|
ExpressionWithContext.withContext(ifFalseBlock, bindings)
|
||||||
}
|
}
|
||||||
| InternalExpressionValue.IEvBool(true) => {
|
| InternalExpressionValue.IEvBool(true) => {
|
||||||
let ifTrueBlock = eBlock(list{ifTrue})
|
let ifTrueBlock = eBlock(list{ifTrue})
|
||||||
ExpressionWithContext.withContext(ifTrueBlock, bindings)->Ok
|
ExpressionWithContext.withContext(ifTrueBlock, bindings)
|
||||||
}
|
}
|
||||||
| _ => REExpectedType("Boolean", "")->Error
|
| _ => REExpectedType("Boolean", "")->Reducer_ErrorValue.toException
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let expandExpressionList = (aList, bindings: ExpressionT.bindings, accessors): result<
|
let expandExpressionList = (
|
||||||
expressionWithContext,
|
aList,
|
||||||
errorValue,
|
bindings: ExpressionT.bindings,
|
||||||
> =>
|
accessors,
|
||||||
|
): expressionWithContext =>
|
||||||
switch aList {
|
switch aList {
|
||||||
| list{
|
| list{
|
||||||
ExpressionT.EValue(IEvCall("$$_bindStatement_$$")),
|
ExpressionT.EValue(IEvCall("$$_bindStatement_$$")),
|
||||||
|
@ -185,11 +179,11 @@ let dispatchMacroCall = (
|
||||||
doLambdaDefinition(bindings, parameters, lambdaDefinition)
|
doLambdaDefinition(bindings, parameters, lambdaDefinition)
|
||||||
| list{ExpressionT.EValue(IEvCall("$$_ternary_$$")), condition, ifTrue, ifFalse} =>
|
| list{ExpressionT.EValue(IEvCall("$$_ternary_$$")), condition, ifTrue, ifFalse} =>
|
||||||
doTernary(condition, ifTrue, ifFalse, bindings, accessors)
|
doTernary(condition, ifTrue, ifFalse, bindings, accessors)
|
||||||
| _ => ExpressionWithContext.noContext(ExpressionT.EList(aList))->Ok
|
| _ => ExpressionWithContext.noContext(ExpressionT.EList(aList))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch macroExpression {
|
switch macroExpression {
|
||||||
| EList(aList) => expandExpressionList(aList, bindings, accessors)
|
| EList(aList) => expandExpressionList(aList, bindings, accessors)
|
||||||
| _ => ExpressionWithContext.noContext(macroExpression)->Ok
|
| _ => ExpressionWithContext.noContext(macroExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ type errorValue =
|
||||||
|
|
||||||
type t = errorValue
|
type t = errorValue
|
||||||
|
|
||||||
|
exception ErrorException(errorValue)
|
||||||
|
|
||||||
let errorToString = err =>
|
let errorToString = err =>
|
||||||
switch err {
|
switch err {
|
||||||
| REArityError(_oFnName, arity, usedArity) =>
|
| REArityError(_oFnName, arity, usedArity) =>
|
||||||
|
@ -62,3 +64,20 @@ let errorToString = err =>
|
||||||
| RENeedToRun => "Need to run"
|
| RENeedToRun => "Need to run"
|
||||||
| REOther(msg) => `Error: ${msg}`
|
| REOther(msg) => `Error: ${msg}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let fromException = exn =>
|
||||||
|
switch exn {
|
||||||
|
| ErrorException(e) => e
|
||||||
|
| Js.Exn.Error(e) =>
|
||||||
|
switch Js.Exn.message(e) {
|
||||||
|
| Some(message) => REOther(message)
|
||||||
|
| None =>
|
||||||
|
switch Js.Exn.name(e) {
|
||||||
|
| Some(name) => REOther(name)
|
||||||
|
| None => REOther("Unknown error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| _e => REOther("Unknown error")
|
||||||
|
}
|
||||||
|
|
||||||
|
let toException = (errorValue: t) => raise(ErrorException(errorValue))
|
||||||
|
|
|
@ -21,10 +21,10 @@ let rec reduceExpressionInProject = (
|
||||||
expression: t,
|
expression: t,
|
||||||
continuation: T.bindings,
|
continuation: T.bindings,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
): result<InternalExpressionValue.t, 'e> => {
|
): InternalExpressionValue.t => {
|
||||||
// Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`)
|
// Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`)
|
||||||
switch expression {
|
switch expression {
|
||||||
| T.EValue(value) => value->Ok
|
| T.EValue(value) => value
|
||||||
| T.EList(list) =>
|
| T.EList(list) =>
|
||||||
switch list {
|
switch list {
|
||||||
| list{EValue(IEvCall(fName)), ..._args} =>
|
| list{EValue(IEvCall(fName)), ..._args} =>
|
||||||
|
@ -41,20 +41,12 @@ and reduceExpressionList = (
|
||||||
expressions: list<t>,
|
expressions: list<t>,
|
||||||
continuation: T.bindings,
|
continuation: T.bindings,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
): result<InternalExpressionValue.t, 'e> => {
|
): InternalExpressionValue.t => {
|
||||||
let racc: result<
|
let acc: list<InternalExpressionValue.t> =
|
||||||
list<InternalExpressionValue.t>,
|
expressions->Belt.List.reduceReverse(list{}, (acc, each: t) =>
|
||||||
'e,
|
acc->Belt.List.add(each->reduceExpressionInProject(continuation, accessors))
|
||||||
> = expressions->Belt.List.reduceReverse(Ok(list{}), (racc, each: t) =>
|
|
||||||
racc->Result.flatMap(acc => {
|
|
||||||
each
|
|
||||||
->reduceExpressionInProject(continuation, accessors)
|
|
||||||
->Result.map(newNode => {
|
|
||||||
acc->Belt.List.add(newNode)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
racc->Result.flatMap(acc => acc->reduceValueList(accessors))
|
acc->reduceValueList(accessors)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -63,48 +55,34 @@ and reduceExpressionList = (
|
||||||
and reduceValueList = (
|
and reduceValueList = (
|
||||||
valueList: list<InternalExpressionValue.t>,
|
valueList: list<InternalExpressionValue.t>,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
): result<InternalExpressionValue.t, 'e> =>
|
): InternalExpressionValue.t =>
|
||||||
switch valueList {
|
switch valueList {
|
||||||
| list{IEvCall(fName), ...args} => {
|
| list{IEvCall(fName), ...args} => {
|
||||||
let rCheckedArgs = switch fName {
|
let checkedArgs = switch fName {
|
||||||
| "$_setBindings_$" | "$_setTypeOfBindings_$" | "$_setTypeAliasBindings_$" => args->Ok
|
| "$_setBindings_$" | "$_setTypeOfBindings_$" | "$_setTypeAliasBindings_$" => args
|
||||||
| _ => args->Lambda.checkIfReduced
|
| _ => args->Lambda.checkIfReduced
|
||||||
}
|
}
|
||||||
|
|
||||||
rCheckedArgs->Result.flatMap(checkedArgs =>
|
|
||||||
(fName, checkedArgs->Belt.List.toArray)->BuiltIn.dispatch(
|
(fName, checkedArgs->Belt.List.toArray)->BuiltIn.dispatch(
|
||||||
accessors,
|
accessors,
|
||||||
reduceExpressionInProject,
|
reduceExpressionInProject,
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
| list{IEvLambda(_)} =>
|
| list{IEvLambda(_)} =>
|
||||||
// TODO: remove on solving issue#558
|
// TODO: remove on solving issue#558
|
||||||
valueList
|
valueList->Lambda.checkIfReduced->Belt.List.toArray->InternalExpressionValue.IEvArray
|
||||||
->Lambda.checkIfReduced
|
|
||||||
->Result.flatMap(reducedValueList =>
|
|
||||||
reducedValueList->Belt.List.toArray->InternalExpressionValue.IEvArray->Ok
|
|
||||||
)
|
|
||||||
| list{IEvLambda(lambdaCall), ...args} =>
|
| list{IEvLambda(lambdaCall), ...args} =>
|
||||||
args
|
args
|
||||||
->Lambda.checkIfReduced
|
->Lambda.checkIfReduced
|
||||||
->Result.flatMap(checkedArgs =>
|
->Lambda.doLambdaCall(lambdaCall, _, accessors, reduceExpressionInProject)
|
||||||
Lambda.doLambdaCall(lambdaCall, checkedArgs, accessors, reduceExpressionInProject)
|
| _ => valueList->Lambda.checkIfReduced->Belt.List.toArray->InternalExpressionValue.IEvArray
|
||||||
)
|
|
||||||
|
|
||||||
| _ =>
|
|
||||||
valueList
|
|
||||||
->Lambda.checkIfReduced
|
|
||||||
->Result.flatMap(reducedValueList =>
|
|
||||||
reducedValueList->Belt.List.toArray->InternalExpressionValue.IEvArray->Ok
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let reduceReturningBindings = (
|
let reduceReturningBindings = (
|
||||||
expression: t,
|
expression: t,
|
||||||
continuation: T.bindings,
|
continuation: T.bindings,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
): (result<InternalExpressionValue.t, 'e>, T.bindings) => {
|
): (InternalExpressionValue.t, T.bindings) => {
|
||||||
let states = accessors.states
|
let states = accessors.states
|
||||||
let result = reduceExpressionInProject(expression, continuation, accessors)
|
let result = reduceExpressionInProject(expression, continuation, accessors)
|
||||||
(result, states.continuation)
|
(result, states.continuation)
|
||||||
|
@ -118,7 +96,11 @@ module BackCompatible = {
|
||||||
|
|
||||||
let evaluate = (expression: t): result<InternalExpressionValue.t, errorValue> => {
|
let evaluate = (expression: t): result<InternalExpressionValue.t, errorValue> => {
|
||||||
let accessors = ProjectAccessorsT.identityAccessors
|
let accessors = ProjectAccessorsT.identityAccessors
|
||||||
expression->reduceExpressionInProject(accessors.stdLib, accessors)
|
try {
|
||||||
|
expression->reduceExpressionInProject(accessors.stdLib, accessors)->Ok
|
||||||
|
} catch {
|
||||||
|
| exn => Reducer_ErrorValue.fromException(exn)->Error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let evaluateString = (peggyCode: string): result<InternalExpressionValue.t, errorValue> =>
|
let evaluateString = (peggyCode: string): result<InternalExpressionValue.t, errorValue> =>
|
||||||
|
|
|
@ -18,12 +18,14 @@ type expressionWithContext =
|
||||||
| ExpressionWithContext(expression, context)
|
| ExpressionWithContext(expression, context)
|
||||||
| ExpressionNoContext(expression)
|
| ExpressionNoContext(expression)
|
||||||
|
|
||||||
|
type t = expressionWithContext
|
||||||
|
|
||||||
let callReducer = (
|
let callReducer = (
|
||||||
expressionWithContext: expressionWithContext,
|
expressionWithContext: expressionWithContext,
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: ProjectReducerFnT.t,
|
reducer: ProjectReducerFnT.t,
|
||||||
): result<internalExpressionValue, errorValue> => {
|
): internalExpressionValue => {
|
||||||
switch expressionWithContext {
|
switch expressionWithContext {
|
||||||
| ExpressionNoContext(expr) =>
|
| ExpressionNoContext(expr) =>
|
||||||
// Js.log(`callReducer: bindings ${Bindings.toString(bindings)} expr ${ExpressionT.toString(expr)}`)
|
// Js.log(`callReducer: bindings ${Bindings.toString(bindings)} expr ${ExpressionT.toString(expr)}`)
|
||||||
|
@ -51,3 +53,10 @@ let toStringResult = rExpressionWithContext =>
|
||||||
| Ok(expressionWithContext) => `Ok(${toString(expressionWithContext)})`
|
| Ok(expressionWithContext) => `Ok(${toString(expressionWithContext)})`
|
||||||
| Error(errorValue) => ErrorValue.errorToString(errorValue)
|
| Error(errorValue) => ErrorValue.errorToString(errorValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let resultToValue = (rExpressionWithContext: result<t, errorValue>): t => {
|
||||||
|
switch rExpressionWithContext {
|
||||||
|
| Ok(expressionWithContext) => expressionWithContext
|
||||||
|
| Error(errorValue) => ErrorValue.toException(errorValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
module ErrorValue = Reducer_ErrorValue
|
module ErrorValue = Reducer_ErrorValue
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module Result = Belt.Result
|
|
||||||
module Bindings = Reducer_Bindings
|
module Bindings = Reducer_Bindings
|
||||||
|
|
||||||
type errorValue = Reducer_ErrorValue.errorValue
|
type errorValue = Reducer_ErrorValue.errorValue
|
||||||
|
@ -10,19 +9,15 @@ type internalExpressionValue = InternalExpressionValue.t
|
||||||
|
|
||||||
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
||||||
|
|
||||||
let rec replaceSymbols = (bindings: ExpressionT.bindings, expression: expression): result<
|
let rec replaceSymbols = (bindings: ExpressionT.bindings, expression: expression): expression =>
|
||||||
expression,
|
|
||||||
errorValue,
|
|
||||||
> =>
|
|
||||||
switch expression {
|
switch expression {
|
||||||
| ExpressionT.EValue(value) =>
|
| ExpressionT.EValue(value) => replaceSymbolOnValue(bindings, value)->ExpressionT.EValue
|
||||||
replaceSymbolOnValue(bindings, value)->Result.map(evValue => evValue->ExpressionT.EValue)
|
|
||||||
| ExpressionT.EList(list) =>
|
| ExpressionT.EList(list) =>
|
||||||
switch list {
|
switch list {
|
||||||
| list{EValue(IEvCall(fName)), ..._args} =>
|
| list{EValue(IEvCall(fName)), ..._args} =>
|
||||||
switch isMacroName(fName) {
|
switch isMacroName(fName) {
|
||||||
// A macro reduces itself so we dont dive in it
|
// A macro reduces itself so we dont dive in it
|
||||||
| true => expression->Ok
|
| true => expression
|
||||||
| false => replaceSymbolsOnExpressionList(bindings, list)
|
| false => replaceSymbolsOnExpressionList(bindings, list)
|
||||||
}
|
}
|
||||||
| _ => replaceSymbolsOnExpressionList(bindings, list)
|
| _ => replaceSymbolsOnExpressionList(bindings, list)
|
||||||
|
@ -30,23 +25,21 @@ let rec replaceSymbols = (bindings: ExpressionT.bindings, expression: expression
|
||||||
}
|
}
|
||||||
|
|
||||||
and replaceSymbolsOnExpressionList = (bindings, list) => {
|
and replaceSymbolsOnExpressionList = (bindings, list) => {
|
||||||
let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) =>
|
let racc =
|
||||||
racc->Result.flatMap(acc => {
|
list->Belt.List.reduceReverse(list{}, (acc, each: expression) =>
|
||||||
replaceSymbols(bindings, each)->Result.flatMap(newNode => {
|
replaceSymbols(bindings, each)->Belt.List.add(acc, _)
|
||||||
acc->Belt.List.add(newNode)->Ok
|
|
||||||
})
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
racc->Result.map(acc => acc->ExpressionT.EList)
|
ExpressionT.EList(racc)
|
||||||
}
|
}
|
||||||
and replaceSymbolOnValue = (bindings, evValue: internalExpressionValue) =>
|
and replaceSymbolOnValue = (bindings, evValue: internalExpressionValue) =>
|
||||||
switch evValue {
|
switch evValue {
|
||||||
| IEvSymbol(symbol) => Bindings.getWithDefault(bindings, symbol, evValue)->Ok
|
| IEvSymbol(symbol) => Bindings.getWithDefault(bindings, symbol, evValue)
|
||||||
| IEvCall(symbol) => Bindings.getWithDefault(bindings, symbol, evValue)->checkIfCallable
|
| IEvCall(symbol) => Bindings.getWithDefault(bindings, symbol, evValue)->checkIfCallable
|
||||||
| _ => evValue->Ok
|
| _ => evValue
|
||||||
}
|
}
|
||||||
and checkIfCallable = (evValue: internalExpressionValue) =>
|
and checkIfCallable = (evValue: internalExpressionValue) =>
|
||||||
switch evValue {
|
switch evValue {
|
||||||
| IEvCall(_) | IEvLambda(_) => evValue->Ok
|
| IEvCall(_) | IEvLambda(_) => evValue
|
||||||
| _ => ErrorValue.RENotAFunction(InternalExpressionValue.toString(evValue))->Error
|
| _ =>
|
||||||
|
ErrorValue.RENotAFunction(InternalExpressionValue.toString(evValue))->ErrorValue.toException
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,27 +23,25 @@ let checkArity = (
|
||||||
let argsLength = Belt.List.length(args)
|
let argsLength = Belt.List.length(args)
|
||||||
let parametersLength = Js.Array2.length(lambdaValue.parameters)
|
let parametersLength = Js.Array2.length(lambdaValue.parameters)
|
||||||
if argsLength !== parametersLength {
|
if argsLength !== parametersLength {
|
||||||
ErrorValue.REArityError(None, parametersLength, argsLength)->Error
|
ErrorValue.REArityError(None, parametersLength, argsLength)->ErrorValue.toException
|
||||||
} else {
|
} else {
|
||||||
args->Ok
|
args
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let exprOrFFI = castInternalCodeToExpression(lambdaValue.body)
|
let exprOrFFI = castInternalCodeToExpression(lambdaValue.body)
|
||||||
switch exprOrFFI {
|
switch exprOrFFI {
|
||||||
| NotFFI(_) => reallyCheck
|
| NotFFI(_) => reallyCheck
|
||||||
| FFI(_) => args->Ok
|
| FFI(_) => args
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let checkIfReduced = (args: list<internalExpressionValue>) =>
|
let checkIfReduced = (args: list<internalExpressionValue>) =>
|
||||||
args->Belt.List.reduceReverse(Ok(list{}), (rAcc, arg) =>
|
args->Belt.List.reduceReverse(list{}, (acc, arg) =>
|
||||||
rAcc->Result.flatMap(acc =>
|
|
||||||
switch arg {
|
switch arg {
|
||||||
| IEvSymbol(symbol) => ErrorValue.RESymbolNotFound(symbol)->Error
|
| IEvSymbol(symbol) => ErrorValue.RESymbolNotFound(symbol)->ErrorValue.toException
|
||||||
| _ => list{arg, ...acc}->Ok
|
| _ => list{arg, ...acc}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
let caseNotFFI = (
|
let caseNotFFI = (
|
||||||
lambdaValue: ExpressionValue.lambdaValue,
|
lambdaValue: ExpressionValue.lambdaValue,
|
||||||
|
@ -63,7 +61,10 @@ let caseNotFFI = (
|
||||||
}
|
}
|
||||||
|
|
||||||
let caseFFI = (ffiFn: ExpressionT.ffiFn, args, accessors: ProjectAccessorsT.t) => {
|
let caseFFI = (ffiFn: ExpressionT.ffiFn, args, accessors: ProjectAccessorsT.t) => {
|
||||||
ffiFn(args->Belt.List.toArray, accessors.environment)
|
switch ffiFn(args->Belt.List.toArray, accessors.environment) {
|
||||||
|
| Ok(value) => value
|
||||||
|
| Error(value) => value->ErrorValue.toException
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let applyParametersToLambda = (
|
let applyParametersToLambda = (
|
||||||
|
@ -71,16 +72,13 @@ let applyParametersToLambda = (
|
||||||
args,
|
args,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: ProjectReducerFnT.t,
|
reducer: ProjectReducerFnT.t,
|
||||||
): result<internalExpressionValue, 'e> => {
|
): internalExpressionValue => {
|
||||||
checkArity(lambdaValue, args)->Result.flatMap(args =>
|
let args = checkArity(lambdaValue, args)->checkIfReduced
|
||||||
checkIfReduced(args)->Result.flatMap(args => {
|
|
||||||
let exprOrFFI = castInternalCodeToExpression(lambdaValue.body)
|
let exprOrFFI = castInternalCodeToExpression(lambdaValue.body)
|
||||||
switch exprOrFFI {
|
switch exprOrFFI {
|
||||||
| NotFFI(expr) => caseNotFFI(lambdaValue, expr, args, accessors, reducer)
|
| NotFFI(expr) => caseNotFFI(lambdaValue, expr, args, accessors, reducer)
|
||||||
| FFI(ffiFn) => caseFFI(ffiFn, args, accessors)
|
| FFI(ffiFn) => caseFFI(ffiFn, args, accessors)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let doLambdaCall = (
|
let doLambdaCall = (
|
||||||
|
@ -95,7 +93,7 @@ let foreignFunctionInterface = (
|
||||||
argArray: array<internalExpressionValue>,
|
argArray: array<internalExpressionValue>,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
reducer: ProjectReducerFnT.t,
|
reducer: ProjectReducerFnT.t,
|
||||||
): result<internalExpressionValue, Reducer_ErrorValue.errorValue> => {
|
): internalExpressionValue => {
|
||||||
let args = argArray->Belt.List.fromArray
|
let args = argArray->Belt.List.fromArray
|
||||||
applyParametersToLambda(lambdaValue, args, accessors, reducer)
|
applyParametersToLambda(lambdaValue, args, accessors, reducer)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,32 +10,34 @@ type expression = ExpressionT.expression
|
||||||
type internalExpressionValue = InternalExpressionValue.t
|
type internalExpressionValue = InternalExpressionValue.t
|
||||||
type expressionWithContext = ExpressionWithContext.expressionWithContext
|
type expressionWithContext = ExpressionWithContext.expressionWithContext
|
||||||
|
|
||||||
let expandMacroCall = (
|
let expandMacroCallRs = (
|
||||||
macroExpression: expression,
|
macroExpression: expression,
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
reduceExpression: ProjectReducerFnT.t,
|
reduceExpression: ProjectReducerFnT.t,
|
||||||
): result<expressionWithContext, 'e> =>
|
): result<expressionWithContext, 'e> =>
|
||||||
|
try {
|
||||||
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(
|
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(
|
||||||
macroExpression,
|
macroExpression,
|
||||||
bindings,
|
bindings,
|
||||||
accessors,
|
accessors,
|
||||||
reduceExpression,
|
reduceExpression,
|
||||||
)
|
)->Ok
|
||||||
|
} catch {
|
||||||
|
| exn => Reducer_ErrorValue.fromException(exn)->Error
|
||||||
|
}
|
||||||
|
|
||||||
let doMacroCall = (
|
let doMacroCall = (
|
||||||
macroExpression: expression,
|
macroExpression: expression,
|
||||||
bindings: ExpressionT.bindings,
|
bindings: ExpressionT.bindings,
|
||||||
accessors: ProjectAccessorsT.t,
|
accessors: ProjectAccessorsT.t,
|
||||||
reduceExpression: ProjectReducerFnT.t,
|
reduceExpression: ProjectReducerFnT.t,
|
||||||
): result<internalExpressionValue, 'e> =>
|
): internalExpressionValue =>
|
||||||
expandMacroCall(
|
Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(
|
||||||
macroExpression,
|
macroExpression,
|
||||||
bindings,
|
bindings,
|
||||||
(accessors: ProjectAccessorsT.t),
|
(accessors: ProjectAccessorsT.t),
|
||||||
(reduceExpression: ProjectReducerFnT.t),
|
(reduceExpression: ProjectReducerFnT.t),
|
||||||
)->Result.flatMap(expressionWithContext =>
|
)->ExpressionWithContext.callReducer(bindings, accessors, reduceExpression)
|
||||||
ExpressionWithContext.callReducer(expressionWithContext, bindings, accessors, reduceExpression)
|
|
||||||
)
|
|
||||||
|
|
||||||
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$")
|
||||||
|
|
|
@ -82,3 +82,9 @@ type optionFfiFnReturningResult = (
|
||||||
type expressionOrFFI =
|
type expressionOrFFI =
|
||||||
| NotFFI(expression)
|
| NotFFI(expression)
|
||||||
| FFI(ffiFn)
|
| FFI(ffiFn)
|
||||||
|
|
||||||
|
let resultToValue = (rExpression: result<t, Reducer_ErrorValue.t>): t =>
|
||||||
|
switch rExpression {
|
||||||
|
| Ok(expression) => expression
|
||||||
|
| Error(errorValue) => Reducer_ErrorValue.toException(errorValue)
|
||||||
|
}
|
||||||
|
|
|
@ -15,17 +15,13 @@ let ievFromTypeExpression = (
|
||||||
let sourceCode = `type ${sIndex}=${typeExpressionSourceCode}`
|
let sourceCode = `type ${sIndex}=${typeExpressionSourceCode}`
|
||||||
Reducer_Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr => {
|
Reducer_Expression.BackCompatible.parse(sourceCode)->Belt.Result.flatMap(expr => {
|
||||||
let accessors = ProjectAccessorsT.identityAccessors
|
let accessors = ProjectAccessorsT.identityAccessors
|
||||||
let result = reducerFn(expr, Bindings.emptyBindings, accessors)
|
let _result = reducerFn(expr, Bindings.emptyBindings, accessors)
|
||||||
let nameSpace = accessors.states.continuation
|
let nameSpace = accessors.states.continuation
|
||||||
|
|
||||||
switch result {
|
|
||||||
| Ok(_) =>
|
|
||||||
switch Bindings.getType(nameSpace, sIndex) {
|
switch Bindings.getType(nameSpace, sIndex) {
|
||||||
| Some(value) => value->Ok
|
| Some(value) => value->Ok
|
||||||
| None => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-none"))
|
| None => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-none"))
|
||||||
}
|
}
|
||||||
| err => err
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -244,3 +244,9 @@ let nameSpaceGet = (nameSpace: nameSpace, key: string): option<t> => {
|
||||||
let NameSpace(container) = nameSpace
|
let NameSpace(container) = nameSpace
|
||||||
container->Belt.Map.String.get(key)
|
container->Belt.Map.String.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let resultToValue = (rExpression: result<t, Reducer_ErrorValue.t>): t =>
|
||||||
|
switch rExpression {
|
||||||
|
| Ok(expression) => expression
|
||||||
|
| Error(errorValue) => Reducer_ErrorValue.toException(errorValue)
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -183,17 +183,6 @@ let buildExpression = (this: t): t => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let wrappedReducer = (
|
|
||||||
rExpression: T.expressionArgumentType,
|
|
||||||
aContinuation: T.continuation,
|
|
||||||
accessors: ProjectAccessorsT.t,
|
|
||||||
): T.resultArgumentType => {
|
|
||||||
Belt.Result.flatMap(
|
|
||||||
rExpression,
|
|
||||||
Reducer_Expression.reduceExpressionInProject(_, aContinuation, accessors),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let doBuildResult = (
|
let doBuildResult = (
|
||||||
this: t,
|
this: t,
|
||||||
aContinuation: T.continuation,
|
aContinuation: T.continuation,
|
||||||
|
@ -202,9 +191,12 @@ let doBuildResult = (
|
||||||
this
|
this
|
||||||
->getExpression
|
->getExpression
|
||||||
->Belt.Option.map(
|
->Belt.Option.map(
|
||||||
Belt.Result.flatMap(
|
Belt.Result.flatMap(_, expression =>
|
||||||
_,
|
try {
|
||||||
Reducer_Expression.reduceExpressionInProject(_, aContinuation, accessors),
|
Reducer_Expression.reduceExpressionInProject(expression, aContinuation, accessors)->Ok
|
||||||
|
} catch {
|
||||||
|
| exn => Reducer_ErrorValue.fromException(exn)->Error
|
||||||
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,4 @@ module ExpressionT = Reducer_Expression_T
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
module ProjectAccessorsT = ReducerProject_ProjectAccessors_T
|
||||||
|
|
||||||
type t = (
|
type t = (ExpressionT.t, ExpressionT.bindings, ProjectAccessorsT.t) => InternalExpressionValue.t
|
||||||
ExpressionT.t,
|
|
||||||
ExpressionT.bindings,
|
|
||||||
ProjectAccessorsT.t,
|
|
||||||
) => result<InternalExpressionValue.t, Reducer_ErrorValue.errorValue>
|
|
||||||
|
|
|
@ -5,912 +5,23 @@ running `rescript convert -all` on Rationale https://github.com/jonlaing/rationa
|
||||||
|
|
||||||
let equals = (a, b) => a === b
|
let equals = (a, b) => a === b
|
||||||
|
|
||||||
module FloatFloatMap = {
|
module A = E_A
|
||||||
module Id = Belt.Id.MakeComparable({
|
module A2 = E_A2
|
||||||
type t = float
|
module B = E_B
|
||||||
let cmp: (float, float) => int = Pervasives.compare
|
module Dict = E_Dict
|
||||||
})
|
module F = E_F
|
||||||
|
module Float = E_Float
|
||||||
type t = Belt.MutableMap.t<Id.t, float, Id.identity>
|
module FloatFloatMap = E_FloatFloatMap
|
||||||
|
module I = E_I
|
||||||
let fromArray = (ar: array<(float, float)>) => Belt.MutableMap.fromArray(ar, ~id=module(Id))
|
module Int = E_Int
|
||||||
let toArray = (t: t): array<(float, float)> => Belt.MutableMap.toArray(t)
|
module J = E_J
|
||||||
let empty = () => Belt.MutableMap.make(~id=module(Id))
|
module JsDate = E_JsDate
|
||||||
let increment = (el, t: t) =>
|
module L = E_L
|
||||||
Belt.MutableMap.update(t, el, x =>
|
module O = E_O
|
||||||
switch x {
|
module O2 = E_O2
|
||||||
| Some(n) => Some(n +. 1.0)
|
module R = E_R
|
||||||
| None => Some(1.0)
|
module R2 = E_R2
|
||||||
}
|
module S = E_S
|
||||||
)
|
module Tuple2 = E_Tuple2
|
||||||
|
module Tuple3 = E_Tuple3
|
||||||
let get = (el, t: t) => Belt.MutableMap.get(t, el)
|
module U = E_U
|
||||||
let fmap = (fn, t: t) => Belt.MutableMap.map(t, fn)
|
|
||||||
let partition = (fn, t: t) => {
|
|
||||||
let (match, noMatch) = Belt.Array.partition(toArray(t), fn)
|
|
||||||
(fromArray(match), fromArray(noMatch))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module Int = {
|
|
||||||
let max = (i1: int, i2: int) => i1 > i2 ? i1 : i2
|
|
||||||
let random = (~min, ~max) => Js.Math.random_int(min, max)
|
|
||||||
}
|
|
||||||
/* Utils */
|
|
||||||
module U = {
|
|
||||||
let isEqual = \"=="
|
|
||||||
let toA = a => [a]
|
|
||||||
let id = e => e
|
|
||||||
}
|
|
||||||
|
|
||||||
module Tuple2 = {
|
|
||||||
let first = (v: ('a, 'b)) => {
|
|
||||||
let (a, _) = v
|
|
||||||
a
|
|
||||||
}
|
|
||||||
let second = (v: ('a, 'b)) => {
|
|
||||||
let (_, b) = v
|
|
||||||
b
|
|
||||||
}
|
|
||||||
let toFnCall = (fn, (a1, a2)) => fn(a1, a2)
|
|
||||||
}
|
|
||||||
|
|
||||||
module Tuple3 = {
|
|
||||||
let toFnCall = (fn, (a1, a2, a3)) => fn(a1, a2, a3)
|
|
||||||
}
|
|
||||||
|
|
||||||
module O = {
|
|
||||||
let dimap = (sFn, rFn, e) =>
|
|
||||||
switch e {
|
|
||||||
| Some(r) => sFn(r)
|
|
||||||
| None => rFn()
|
|
||||||
}
|
|
||||||
()
|
|
||||||
let fmap = (f: 'a => 'b, x: option<'a>): option<'b> => {
|
|
||||||
switch x {
|
|
||||||
| None => None
|
|
||||||
| Some(x') => Some(f(x'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let bind = (o, f) =>
|
|
||||||
switch o {
|
|
||||||
| None => None
|
|
||||||
| Some(a) => f(a)
|
|
||||||
}
|
|
||||||
let default = (d, o) =>
|
|
||||||
switch o {
|
|
||||||
| None => d
|
|
||||||
| Some(a) => a
|
|
||||||
}
|
|
||||||
let defaultFn = (d, o) =>
|
|
||||||
switch o {
|
|
||||||
| None => d()
|
|
||||||
| Some(a) => a
|
|
||||||
}
|
|
||||||
let isSome = o =>
|
|
||||||
switch o {
|
|
||||||
| Some(_) => true
|
|
||||||
| _ => false
|
|
||||||
}
|
|
||||||
let isNone = o =>
|
|
||||||
switch o {
|
|
||||||
| None => true
|
|
||||||
| _ => false
|
|
||||||
}
|
|
||||||
let toExn = (err, o) =>
|
|
||||||
switch o {
|
|
||||||
| None => raise(Failure(err))
|
|
||||||
| Some(a) => a
|
|
||||||
}
|
|
||||||
|
|
||||||
let some = a => Some(a)
|
|
||||||
let firstSome = (a, b) =>
|
|
||||||
switch a {
|
|
||||||
| None => b
|
|
||||||
| _ => a
|
|
||||||
}
|
|
||||||
|
|
||||||
let toExt = toExn
|
|
||||||
|
|
||||||
let flatten = o =>
|
|
||||||
switch o {
|
|
||||||
| None => None
|
|
||||||
| Some(x) => x
|
|
||||||
}
|
|
||||||
|
|
||||||
let apply = (o, a) =>
|
|
||||||
switch o {
|
|
||||||
| Some(f) => bind(a, b => some(f(b)))
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
let flatApply = (fn, b) => apply(fn, Some(b)) |> flatten
|
|
||||||
|
|
||||||
let toBool = opt =>
|
|
||||||
switch opt {
|
|
||||||
| Some(_) => true
|
|
||||||
| _ => false
|
|
||||||
}
|
|
||||||
|
|
||||||
let ffmap = (fn, r) =>
|
|
||||||
switch r {
|
|
||||||
| Some(sm) => fn(sm)
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
|
|
||||||
let toString = opt =>
|
|
||||||
switch opt {
|
|
||||||
| Some(s) => s
|
|
||||||
| _ => ""
|
|
||||||
}
|
|
||||||
|
|
||||||
let toResult = (error, e) =>
|
|
||||||
switch e {
|
|
||||||
| Some(r) => Belt.Result.Ok(r)
|
|
||||||
| None => Error(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
let compare = (compare, f1: option<float>, f2: option<float>) =>
|
|
||||||
switch (f1, f2) {
|
|
||||||
| (Some(f1), Some(f2)) => Some(compare(f1, f2) ? f1 : f2)
|
|
||||||
| (Some(f1), None) => Some(f1)
|
|
||||||
| (None, Some(f2)) => Some(f2)
|
|
||||||
| (None, None) => None
|
|
||||||
}
|
|
||||||
|
|
||||||
let min = compare(\"<")
|
|
||||||
let max = compare(\">")
|
|
||||||
}
|
|
||||||
|
|
||||||
module O2 = {
|
|
||||||
let default = (a, b) => O.default(b, a)
|
|
||||||
let defaultFn = (a, b) => O.defaultFn(b, a)
|
|
||||||
let toExn = (a, b) => O.toExn(b, a)
|
|
||||||
let fmap = (a, b) => O.fmap(b, a)
|
|
||||||
let toResult = (a, b) => O.toResult(b, a)
|
|
||||||
let bind = (a, b) => O.bind(b, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Functions */
|
|
||||||
module F = {
|
|
||||||
let pipe = (f, g, x) => g(f(x))
|
|
||||||
let compose = (f, g, x) => f(g(x))
|
|
||||||
let flip = (f, a, b) => f(b, a)
|
|
||||||
let always = (x, _y) => x
|
|
||||||
|
|
||||||
let apply = (a, e) => a |> e
|
|
||||||
|
|
||||||
let flatten2Callbacks = (fn1, fn2, fnlast) =>
|
|
||||||
fn1(response1 => fn2(response2 => fnlast(response1, response2)))
|
|
||||||
|
|
||||||
let flatten3Callbacks = (fn1, fn2, fn3, fnlast) =>
|
|
||||||
fn1(response1 => fn2(response2 => fn3(response3 => fnlast(response1, response2, response3))))
|
|
||||||
|
|
||||||
let flatten4Callbacks = (fn1, fn2, fn3, fn4, fnlast) =>
|
|
||||||
fn1(response1 =>
|
|
||||||
fn2(response2 =>
|
|
||||||
fn3(response3 => fn4(response4 => fnlast(response1, response2, response3, response4)))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module Bool = {
|
|
||||||
type t = bool
|
|
||||||
let toString = (t: t) => t ? "TRUE" : "FALSE"
|
|
||||||
let fromString = str => str == "TRUE" ? true : false
|
|
||||||
|
|
||||||
module O = {
|
|
||||||
let toBool = opt =>
|
|
||||||
switch opt {
|
|
||||||
| Some(true) => true
|
|
||||||
| _ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module Float = {
|
|
||||||
let with2DigitsPrecision = Js.Float.toPrecisionWithPrecision(_, ~digits=2)
|
|
||||||
let with3DigitsPrecision = Js.Float.toPrecisionWithPrecision(_, ~digits=3)
|
|
||||||
let toFixed = Js.Float.toFixed
|
|
||||||
let toString = Js.Float.toString
|
|
||||||
let isFinite = Js.Float.isFinite
|
|
||||||
let toInt = Belt.Float.toInt
|
|
||||||
}
|
|
||||||
|
|
||||||
module I = {
|
|
||||||
let increment = n => n + 1
|
|
||||||
let decrement = n => n - 1
|
|
||||||
let toString = Js.Int.toString
|
|
||||||
let toFloat = Js.Int.toFloat
|
|
||||||
}
|
|
||||||
|
|
||||||
exception Assertion(string)
|
|
||||||
|
|
||||||
/* R for Result */
|
|
||||||
module R = {
|
|
||||||
open Belt.Result
|
|
||||||
let result = (okF, errF, r) =>
|
|
||||||
switch r {
|
|
||||||
| Ok(a) => okF(a)
|
|
||||||
| Error(err) => errF(err)
|
|
||||||
}
|
|
||||||
let id = e => e |> result(U.id, U.id)
|
|
||||||
let isOk = Belt.Result.isOk
|
|
||||||
let getError = (r: result<'a, 'b>) =>
|
|
||||||
switch r {
|
|
||||||
| Ok(_) => None
|
|
||||||
| Error(e) => Some(e)
|
|
||||||
}
|
|
||||||
let fmap = (f: 'a => 'b, r: result<'a, 'c>): result<'b, 'c> => {
|
|
||||||
switch r {
|
|
||||||
| Ok(r') => Ok(f(r'))
|
|
||||||
| Error(err) => Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let bind = (r, f) =>
|
|
||||||
switch r {
|
|
||||||
| Ok(a) => f(a)
|
|
||||||
| Error(err) => Error(err)
|
|
||||||
}
|
|
||||||
let toExn = (msg: string, x: result<'a, 'b>): 'a =>
|
|
||||||
switch x {
|
|
||||||
| Ok(r) => r
|
|
||||||
| Error(_) => raise(Assertion(msg))
|
|
||||||
}
|
|
||||||
let toExnFnString = (errorToStringFn, o) =>
|
|
||||||
switch o {
|
|
||||||
| Ok(r) => r
|
|
||||||
| Error(r) => raise(Assertion(errorToStringFn(r)))
|
|
||||||
}
|
|
||||||
let default = (default, res: Belt.Result.t<'a, 'b>) =>
|
|
||||||
switch res {
|
|
||||||
| Ok(r) => r
|
|
||||||
| Error(_) => default
|
|
||||||
}
|
|
||||||
let merge = (a, b) =>
|
|
||||||
switch (a, b) {
|
|
||||||
| (Error(e), _) => Error(e)
|
|
||||||
| (_, Error(e)) => Error(e)
|
|
||||||
| (Ok(a), Ok(b)) => Ok((a, b))
|
|
||||||
}
|
|
||||||
let toOption = (e: Belt.Result.t<'a, 'b>) =>
|
|
||||||
switch e {
|
|
||||||
| Ok(r) => Some(r)
|
|
||||||
| Error(_) => None
|
|
||||||
}
|
|
||||||
|
|
||||||
let errorIfCondition = (errorCondition, errorMessage, r) =>
|
|
||||||
errorCondition(r) ? Error(errorMessage) : Ok(r)
|
|
||||||
|
|
||||||
let ap = (r, a) =>
|
|
||||||
switch r {
|
|
||||||
| Ok(f) => Ok(f(a))
|
|
||||||
| Error(err) => Error(err)
|
|
||||||
}
|
|
||||||
let ap' = (r, a) =>
|
|
||||||
switch r {
|
|
||||||
| Ok(f) => fmap(f, a)
|
|
||||||
| Error(err) => Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
let liftM2: (('a, 'b) => 'c, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (op, xR, yR) => {
|
|
||||||
ap'(fmap(op, xR), yR)
|
|
||||||
}
|
|
||||||
|
|
||||||
let liftJoin2: (('a, 'b) => result<'c, 'd>, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (
|
|
||||||
op,
|
|
||||||
xR,
|
|
||||||
yR,
|
|
||||||
) => {
|
|
||||||
bind(liftM2(op, xR, yR), x => x)
|
|
||||||
}
|
|
||||||
|
|
||||||
let fmap2 = (f, r) =>
|
|
||||||
switch r {
|
|
||||||
| Ok(r) => r->Ok
|
|
||||||
| Error(x) => x->f->Error
|
|
||||||
}
|
|
||||||
|
|
||||||
//I'm not sure what to call this.
|
|
||||||
let unify = (a: result<'a, 'b>, c: 'b => 'a): 'a =>
|
|
||||||
switch a {
|
|
||||||
| Ok(x) => x
|
|
||||||
| Error(x) => c(x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module R2 = {
|
|
||||||
let fmap = (a, b) => R.fmap(b, a)
|
|
||||||
let bind = (a, b) => R.bind(b, a)
|
|
||||||
|
|
||||||
//Converts result type to change error type only
|
|
||||||
let errMap = (a: result<'a, 'b>, map: 'b => 'c): result<'a, 'c> =>
|
|
||||||
switch a {
|
|
||||||
| Ok(r) => Ok(r)
|
|
||||||
| Error(e) => Error(map(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
let fmap2 = (xR, f) =>
|
|
||||||
switch xR {
|
|
||||||
| Ok(x) => x->Ok
|
|
||||||
| Error(x) => x->f->Error
|
|
||||||
}
|
|
||||||
|
|
||||||
let toExn = (a, b) => R.toExn(b, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
let safe_fn_of_string = (fn, s: string): option<'a> =>
|
|
||||||
try Some(fn(s)) catch {
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
|
|
||||||
module S = {
|
|
||||||
let safe_float = float_of_string->safe_fn_of_string
|
|
||||||
let safe_int = int_of_string->safe_fn_of_string
|
|
||||||
let default = (defaultStr, str) => str == "" ? defaultStr : str
|
|
||||||
}
|
|
||||||
|
|
||||||
module J = {
|
|
||||||
let toString = F.pipe(Js.Json.decodeString, O.default(""))
|
|
||||||
let fromString = Js.Json.string
|
|
||||||
let fromNumber = Js.Json.number
|
|
||||||
|
|
||||||
module O = {
|
|
||||||
let fromString = (str: string) =>
|
|
||||||
switch str {
|
|
||||||
| "" => None
|
|
||||||
| _ => Some(Js.Json.string(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
let toString = (str: option<'a>) =>
|
|
||||||
switch str {
|
|
||||||
| Some(str) => Some(str |> F.pipe(Js.Json.decodeString, O.default("")))
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module JsDate = {
|
|
||||||
let fromString = Js.Date.fromString
|
|
||||||
let now = Js.Date.now
|
|
||||||
let make = Js.Date.make
|
|
||||||
let valueOf = Js.Date.valueOf
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List */
|
|
||||||
module L = {
|
|
||||||
module Util = {
|
|
||||||
let eq = \"=="
|
|
||||||
}
|
|
||||||
let fmap = List.map
|
|
||||||
let get = Belt.List.get
|
|
||||||
let toArray = Array.of_list
|
|
||||||
let fmapi = List.mapi
|
|
||||||
let concat = List.concat
|
|
||||||
let concat' = (xs, ys) => List.append(ys, xs)
|
|
||||||
|
|
||||||
let rec drop = (i, xs) =>
|
|
||||||
switch (i, xs) {
|
|
||||||
| (_, list{}) => list{}
|
|
||||||
| (i, _) if i <= 0 => xs
|
|
||||||
| (i, list{_, ...b}) => drop(i - 1, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
let append = (a, xs) => List.append(xs, list{a})
|
|
||||||
let take = {
|
|
||||||
let rec loop = (i, xs, acc) =>
|
|
||||||
switch (i, xs) {
|
|
||||||
| (i, _) if i <= 0 => acc
|
|
||||||
| (_, list{}) => acc
|
|
||||||
| (i, list{a, ...b}) => loop(i - 1, b, append(a, acc))
|
|
||||||
}
|
|
||||||
(i, xs) => loop(i, xs, list{})
|
|
||||||
}
|
|
||||||
let takeLast = (i, xs) => List.rev(xs) |> take(i) |> List.rev
|
|
||||||
|
|
||||||
let splitAt = (i, xs) => (take(i, xs), takeLast(List.length(xs) - i, xs))
|
|
||||||
let remove = (i, n, xs) => {
|
|
||||||
let (a, b) = splitAt(i, xs)
|
|
||||||
\"@"(a, drop(n, b))
|
|
||||||
}
|
|
||||||
|
|
||||||
let find = List.find
|
|
||||||
let filter = List.filter
|
|
||||||
let for_all = List.for_all
|
|
||||||
let exists = List.exists
|
|
||||||
let sort = List.sort
|
|
||||||
let length = List.length
|
|
||||||
|
|
||||||
let filter_opt = xs => {
|
|
||||||
let rec loop = (l, acc) =>
|
|
||||||
switch l {
|
|
||||||
| list{} => acc
|
|
||||||
| list{hd, ...tl} =>
|
|
||||||
switch hd {
|
|
||||||
| None => loop(tl, acc)
|
|
||||||
| Some(x) => loop(tl, list{x, ...acc})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List.rev(loop(xs, list{}))
|
|
||||||
}
|
|
||||||
|
|
||||||
let containsWith = f => List.exists(f)
|
|
||||||
|
|
||||||
let uniqWithBy = (eq, f, xs) =>
|
|
||||||
List.fold_left(
|
|
||||||
((acc, tacc), v) =>
|
|
||||||
containsWith(eq(f(v)), tacc) ? (acc, tacc) : (append(v, acc), append(f(v), tacc)),
|
|
||||||
(list{}, list{}),
|
|
||||||
xs,
|
|
||||||
) |> fst
|
|
||||||
|
|
||||||
let uniqBy = (f, xs) => uniqWithBy(Util.eq, f, xs)
|
|
||||||
let join = j => List.fold_left((acc, v) => String.length(acc) == 0 ? v : acc ++ (j ++ v), "")
|
|
||||||
|
|
||||||
let head = xs =>
|
|
||||||
switch List.hd(xs) {
|
|
||||||
| exception _ => None
|
|
||||||
| a => Some(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
let uniq = xs => uniqBy(x => x, xs)
|
|
||||||
let flatten = List.flatten
|
|
||||||
let last = xs => xs |> List.rev |> head
|
|
||||||
let append = List.append
|
|
||||||
let getBy = Belt.List.getBy
|
|
||||||
let dropLast = (i, xs) => take(List.length(xs) - i, xs)
|
|
||||||
let containsWith = f => List.exists(f)
|
|
||||||
let contains = x => containsWith(Util.eq(x))
|
|
||||||
|
|
||||||
let reject = pred => List.filter(x => !pred(x))
|
|
||||||
let tail = xs =>
|
|
||||||
switch List.tl(xs) {
|
|
||||||
| exception _ => None
|
|
||||||
| a => Some(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
let init = xs => {
|
|
||||||
O.fmap(List.rev, xs |> List.rev |> tail)
|
|
||||||
}
|
|
||||||
|
|
||||||
let singleton = (x: 'a): list<'a> => list{x}
|
|
||||||
|
|
||||||
let adjust = (f, i, xs) => {
|
|
||||||
let (a, b) = splitAt(i + 1, xs)
|
|
||||||
switch a {
|
|
||||||
| _ if i < 0 => xs
|
|
||||||
| _ if i >= List.length(xs) => xs
|
|
||||||
| list{} => b
|
|
||||||
| list{a} => list{f(a), ...b}
|
|
||||||
| a =>
|
|
||||||
O.fmap(
|
|
||||||
concat'(b),
|
|
||||||
O.bind(init(a), x =>
|
|
||||||
O.fmap(F.flip(append, x), O.fmap(fmap(f), O.fmap(singleton, last(a))))
|
|
||||||
),
|
|
||||||
) |> O.default(xs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let without = (exclude, xs) => reject(x => contains(x, exclude), xs)
|
|
||||||
let update = (x, i, xs) => adjust(F.always(x), i, xs)
|
|
||||||
let iter = List.iter
|
|
||||||
|
|
||||||
let findIndex = {
|
|
||||||
let rec loop = (pred, xs, i) =>
|
|
||||||
switch xs {
|
|
||||||
| list{} => None
|
|
||||||
| list{a, ...b} => pred(a) ? Some(i) : loop(pred, b, i + 1)
|
|
||||||
}
|
|
||||||
(pred, xs) => loop(pred, xs, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
let headSafe = Belt.List.head
|
|
||||||
let tailSafe = Belt.List.tail
|
|
||||||
let headExn = Belt.List.headExn
|
|
||||||
let tailExn = Belt.List.tailExn
|
|
||||||
let zip = Belt.List.zip
|
|
||||||
|
|
||||||
let combinations2: list<'a> => list<('a, 'a)> = xs => {
|
|
||||||
let rec loop: ('a, list<'a>) => list<('a, 'a)> = (x', xs') => {
|
|
||||||
let n = length(xs')
|
|
||||||
if n == 0 {
|
|
||||||
list{}
|
|
||||||
} else {
|
|
||||||
let combs = fmap(y => (x', y), xs')
|
|
||||||
let hd = headExn(xs')
|
|
||||||
let tl = tailExn(xs')
|
|
||||||
concat(list{combs, loop(hd, tl)})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (headSafe(xs), tailSafe(xs)) {
|
|
||||||
| (Some(x'), Some(xs')) => loop(x', xs')
|
|
||||||
| (_, _) => list{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A for Array */
|
|
||||||
module A = {
|
|
||||||
let fmap = Array.map
|
|
||||||
let fmapi = Array.mapi
|
|
||||||
let to_list = Array.to_list
|
|
||||||
let of_list = Array.of_list
|
|
||||||
let length = Array.length
|
|
||||||
let append = Array.append
|
|
||||||
// let empty = [||];
|
|
||||||
let unsafe_get = Array.unsafe_get
|
|
||||||
let get = Belt.Array.get
|
|
||||||
let getBy = Belt.Array.getBy
|
|
||||||
let getIndexBy = Belt.Array.getIndexBy
|
|
||||||
let last = a => get(a, length(a) - 1)
|
|
||||||
let first = get(_, 0)
|
|
||||||
let hasBy = (r, fn) => Belt.Array.getBy(r, fn) |> O.isSome
|
|
||||||
let fold_left = Array.fold_left
|
|
||||||
let fold_right = Array.fold_right
|
|
||||||
let concat = Belt.Array.concat
|
|
||||||
let concatMany = Belt.Array.concatMany
|
|
||||||
let keepMap = Belt.Array.keepMap
|
|
||||||
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
|
|
||||||
let stableSortBy = Belt.SortArray.stableSortBy
|
|
||||||
let toNoneIfEmpty = r => isEmpty(r) ? None : Some(r)
|
|
||||||
let toRanges = (a: array<'a>) =>
|
|
||||||
switch a |> Belt.Array.length {
|
|
||||||
| 0
|
|
||||||
| 1 =>
|
|
||||||
Belt.Result.Error("Must be at least 2 elements")
|
|
||||||
| n =>
|
|
||||||
Belt.Array.makeBy(n - 1, r => r)
|
|
||||||
|> Belt.Array.map(_, index => (
|
|
||||||
Belt.Array.getUnsafe(a, index),
|
|
||||||
Belt.Array.getUnsafe(a, index + 1),
|
|
||||||
))
|
|
||||||
|> (x => Ok(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
let getByFmap = (a, fn, boolCondition) => {
|
|
||||||
let i = ref(0)
|
|
||||||
let finalFunctionValue = ref(None)
|
|
||||||
let length = Belt.Array.length(a)
|
|
||||||
|
|
||||||
while i.contents < length && finalFunctionValue.contents == None {
|
|
||||||
let itemWithFnApplied = Belt.Array.getUnsafe(a, i.contents) |> fn
|
|
||||||
if boolCondition(itemWithFnApplied) {
|
|
||||||
finalFunctionValue := Some(itemWithFnApplied)
|
|
||||||
}
|
|
||||||
i := i.contents + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
finalFunctionValue.contents
|
|
||||||
}
|
|
||||||
|
|
||||||
let tail = Belt.Array.sliceToEnd(_, 1)
|
|
||||||
|
|
||||||
let zip = Belt.Array.zip
|
|
||||||
let unzip = Belt.Array.unzip
|
|
||||||
let zip3 = (a, b, c) =>
|
|
||||||
Belt.Array.zip(a, b)->Belt.Array.zip(c)->Belt.Array.map((((v1, v2), v3)) => (v1, v2, v3))
|
|
||||||
// This zips while taking the longest elements of each array.
|
|
||||||
let zipMaxLength = (array1, array2) => {
|
|
||||||
let maxLength = Int.max(length(array1), length(array2))
|
|
||||||
let result = maxLength |> Belt.Array.makeUninitializedUnsafe
|
|
||||||
for i in 0 to maxLength - 1 {
|
|
||||||
Belt.Array.set(result, i, (get(array1, i), get(array2, i))) |> ignore
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
let asList = (f: list<'a> => list<'a>, r: array<'a>) => r |> to_list |> f |> of_list
|
|
||||||
/* TODO: Is there a better way of doing this? */
|
|
||||||
let uniq = r => asList(L.uniq, r)
|
|
||||||
|
|
||||||
//intersperse([1,2,3], [10,11,12]) => [1,10,2,11,3,12]
|
|
||||||
let intersperse = (a: array<'a>, b: array<'a>) => {
|
|
||||||
let items: ref<array<'a>> = ref([])
|
|
||||||
|
|
||||||
Belt.Array.forEachWithIndex(a, (i, item) =>
|
|
||||||
switch Belt.Array.get(b, i) {
|
|
||||||
| Some(r) => items := append(items.contents, [item, r])
|
|
||||||
| None => items := append(items.contents, [item])
|
|
||||||
}
|
|
||||||
)
|
|
||||||
items.contents
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is like map, but
|
|
||||||
//accumulate((a,b) => a + b, [1,2,3]) => [1, 3, 5]
|
|
||||||
let accumulate = (fn: ('a, 'a) => 'a, items: array<'a>) => {
|
|
||||||
let length = items |> length
|
|
||||||
let empty = Belt.Array.make(length, items |> unsafe_get(_, 0))
|
|
||||||
Belt.Array.forEachWithIndex(items, (index, element) => {
|
|
||||||
let item = switch index {
|
|
||||||
| 0 => element
|
|
||||||
| index => fn(element, unsafe_get(empty, index - 1))
|
|
||||||
}
|
|
||||||
let _ = Belt.Array.set(empty, index, item)
|
|
||||||
})
|
|
||||||
empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo: Is -1 still the indicator that this is false (as is true with
|
|
||||||
// @todo: js findIndex)? Wasn't sure.
|
|
||||||
let findIndex = (e, i) =>
|
|
||||||
Js.Array.findIndex(e, i) |> (
|
|
||||||
r =>
|
|
||||||
switch r {
|
|
||||||
| -1 => None
|
|
||||||
| r => Some(r)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
let filter = Js.Array.filter
|
|
||||||
let joinWith = Js.Array.joinWith
|
|
||||||
let transpose = (xs: array<array<'a>>): array<array<'a>> => {
|
|
||||||
let arr: array<array<'a>> = []
|
|
||||||
for i in 0 to length(xs) - 1 {
|
|
||||||
for j in 0 to length(xs[i]) - 1 {
|
|
||||||
if Js.Array.length(arr) <= j {
|
|
||||||
ignore(Js.Array.push([xs[i][j]], arr))
|
|
||||||
} else {
|
|
||||||
ignore(Js.Array.push(xs[i][j], arr[j]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arr
|
|
||||||
}
|
|
||||||
|
|
||||||
let all = (p: 'a => bool, xs: array<'a>): bool => length(filter(p, xs)) == length(xs)
|
|
||||||
let any = (p: 'a => bool, xs: array<'a>): bool => length(filter(p, xs)) > 0
|
|
||||||
|
|
||||||
module O = {
|
|
||||||
let concatSomes = (optionals: array<option<'a>>): array<'a> =>
|
|
||||||
optionals
|
|
||||||
|> Js.Array.filter(O.isSome)
|
|
||||||
|> Js.Array.map(O.toExn("Warning: This should not have happened"))
|
|
||||||
let defaultEmpty = (o: option<array<'a>>): array<'a> =>
|
|
||||||
switch o {
|
|
||||||
| Some(o) => o
|
|
||||||
| None => []
|
|
||||||
}
|
|
||||||
// REturns `None` there are no non-`None` elements
|
|
||||||
let rec arrSomeToSomeArr = (optionals: array<option<'a>>): option<array<'a>> => {
|
|
||||||
let optionals' = optionals->Belt.List.fromArray
|
|
||||||
switch optionals' {
|
|
||||||
| list{} => []->Some
|
|
||||||
| list{x, ...xs} =>
|
|
||||||
switch x {
|
|
||||||
| Some(_) => xs->Belt.List.toArray->arrSomeToSomeArr
|
|
||||||
| None => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let firstSome = x => Belt.Array.getBy(x, O.isSome)
|
|
||||||
|
|
||||||
let firstSomeFn = (r: array<unit => option<'a>>): option<'a> =>
|
|
||||||
O.flatten(getByFmap(r, l => l(), O.isSome))
|
|
||||||
|
|
||||||
let firstSomeFnWithDefault = (r, default) => firstSomeFn(r)->O2.default(default)
|
|
||||||
|
|
||||||
let openIfAllSome = (optionals: array<option<'a>>): option<array<'a>> => {
|
|
||||||
if all(O.isSome, optionals) {
|
|
||||||
Some(optionals |> fmap(O.toExn("Warning: This should not have happened")))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module R = {
|
|
||||||
let firstErrorOrOpen = (results: array<Belt.Result.t<'a, 'b>>): Belt.Result.t<
|
|
||||||
array<'a>,
|
|
||||||
'b,
|
|
||||||
> => {
|
|
||||||
let bringErrorUp = switch results |> Belt.Array.getBy(_, Belt.Result.isError) {
|
|
||||||
| Some(Belt.Result.Error(err)) => Belt.Result.Error(err)
|
|
||||||
| Some(Belt.Result.Ok(_)) => Belt.Result.Ok(results)
|
|
||||||
| None => Belt.Result.Ok(results)
|
|
||||||
}
|
|
||||||
let forceOpen = (r: array<Belt.Result.t<'a, 'b>>): array<'a> =>
|
|
||||||
r |> Belt.Array.map(_, r => Belt.Result.getExn(r))
|
|
||||||
bringErrorUp |> Belt.Result.map(_, forceOpen)
|
|
||||||
}
|
|
||||||
let filterOk = (x: array<result<'a, 'b>>): array<'a> => fmap(R.toOption, x)->O.concatSomes
|
|
||||||
|
|
||||||
let forM = (x: array<'a>, fn: 'a => result<'b, 'c>): result<array<'b>, 'c> =>
|
|
||||||
firstErrorOrOpen(fmap(fn, x))
|
|
||||||
|
|
||||||
let foldM = (fn: ('c, 'a) => result<'b, 'e>, init: 'c, x: array<'a>): result<'c, 'e> => {
|
|
||||||
let acc = ref(init)
|
|
||||||
let final = ref(Ok())
|
|
||||||
let break = ref(false)
|
|
||||||
let i = ref(0)
|
|
||||||
|
|
||||||
while break.contents != true && i.contents < length(x) {
|
|
||||||
switch fn(acc.contents, x[i.contents]) {
|
|
||||||
| Ok(r) => acc := r
|
|
||||||
| Error(err) => {
|
|
||||||
final := Error(err)
|
|
||||||
break := true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i := i.contents + 1
|
|
||||||
}
|
|
||||||
switch final.contents {
|
|
||||||
| Ok(_) => Ok(acc.contents)
|
|
||||||
| Error(err) => Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module Floats = {
|
|
||||||
type t = array<float>
|
|
||||||
let mean = Jstat.mean
|
|
||||||
let geomean = Jstat.geomean
|
|
||||||
let mode = Jstat.mode
|
|
||||||
let variance = Jstat.variance
|
|
||||||
let stdev = Jstat.stdev
|
|
||||||
let sum = Jstat.sum
|
|
||||||
let product = Jstat.product
|
|
||||||
let random = Js.Math.random_int
|
|
||||||
|
|
||||||
let floatCompare: (float, float) => int = compare
|
|
||||||
let sort = t => {
|
|
||||||
let r = t
|
|
||||||
r |> Array.fast_sort(floatCompare)
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
let getNonFinite = (t: t) => Belt.Array.getBy(t, r => !Js.Float.isFinite(r))
|
|
||||||
let getBelowZero = (t: t) => Belt.Array.getBy(t, r => r < 0.0)
|
|
||||||
|
|
||||||
let isSorted = (t: t): bool =>
|
|
||||||
if Array.length(t) < 1 {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
reduce(zip(t, tail(t)), true, (acc, (first, second)) => acc && first < second)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Passing true for the exclusive parameter excludes both endpoints of the range.
|
|
||||||
//https://jstat.github.io/all.html
|
|
||||||
let percentile = (a, b) => Jstat.percentile(a, b, false)
|
|
||||||
|
|
||||||
// Gives an array with all the differences between values
|
|
||||||
// diff([1,5,3,7]) = [4,-2,4]
|
|
||||||
let diff = (t: t): array<float> =>
|
|
||||||
Belt.Array.zipBy(t, Belt.Array.sliceToEnd(t, 1), (left, right) => right -. left)
|
|
||||||
|
|
||||||
let cumSum = (t: t): array<float> => accumulate((a, b) => a +. b, t)
|
|
||||||
let cumProd = (t: t): array<float> => accumulate((a, b) => a *. b, t)
|
|
||||||
|
|
||||||
exception RangeError(string)
|
|
||||||
let range = (min: float, max: float, n: int): array<float> =>
|
|
||||||
switch n {
|
|
||||||
| 0 => []
|
|
||||||
| 1 => [min]
|
|
||||||
| 2 => [min, max]
|
|
||||||
| _ if min == max => Belt.Array.make(n, min)
|
|
||||||
| _ if n < 0 => raise(RangeError("n must be greater than 0"))
|
|
||||||
| _ if min > max => raise(RangeError("Min value is less then max value"))
|
|
||||||
| _ =>
|
|
||||||
let diff = (max -. min) /. Belt.Float.fromInt(n - 1)
|
|
||||||
Belt.Array.makeBy(n, i => min +. Belt.Float.fromInt(i) *. diff)
|
|
||||||
}
|
|
||||||
|
|
||||||
let min = Js.Math.minMany_float
|
|
||||||
let max = Js.Math.maxMany_float
|
|
||||||
|
|
||||||
module Sorted = {
|
|
||||||
let min = first
|
|
||||||
let max = last
|
|
||||||
let range = (~min=min, ~max=max, a) =>
|
|
||||||
switch (min(a), max(a)) {
|
|
||||||
| (Some(min), Some(max)) => Some(max -. min)
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
|
|
||||||
let binarySearchFirstElementGreaterIndex = (ar: array<'a>, el: 'a) => {
|
|
||||||
let el = Belt.SortArray.binarySearchBy(ar, el, floatCompare)
|
|
||||||
let el = el < 0 ? el * -1 - 1 : el
|
|
||||||
switch el {
|
|
||||||
| e if e >= length(ar) => #overMax
|
|
||||||
| e if e == 0 => #underMin
|
|
||||||
| e => #firstHigher(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let concat = (t1: array<'a>, t2: array<'a>) => Belt.Array.concat(t1, t2)->sort
|
|
||||||
|
|
||||||
let concatMany = (t1: array<array<'a>>) => Belt.Array.concatMany(t1)->sort
|
|
||||||
|
|
||||||
let makeIncrementalUp = (a, b) =>
|
|
||||||
Array.make(b - a + 1, a) |> Array.mapi((i, c) => c + i) |> Belt.Array.map(_, float_of_int)
|
|
||||||
|
|
||||||
let makeIncrementalDown = (a, b) =>
|
|
||||||
Array.make(a - b + 1, a) |> Array.mapi((i, c) => c - i) |> Belt.Array.map(_, float_of_int)
|
|
||||||
|
|
||||||
/*
|
|
||||||
This function goes through a sorted array and divides it into two different clusters:
|
|
||||||
continuous samples and discrete samples. The discrete samples are stored in a mutable map.
|
|
||||||
Samples are thought to be discrete if they have any duplicates.
|
|
||||||
*/
|
|
||||||
let _splitContinuousAndDiscreteForDuplicates = (sortedArray: array<float>) => {
|
|
||||||
let continuous: array<float> = []
|
|
||||||
let discrete = FloatFloatMap.empty()
|
|
||||||
Belt.Array.forEachWithIndex(sortedArray, (index, element) => {
|
|
||||||
let maxIndex = (sortedArray |> Array.length) - 1
|
|
||||||
let possiblySimilarElements = switch index {
|
|
||||||
| 0 => [index + 1]
|
|
||||||
| n if n == maxIndex => [index - 1]
|
|
||||||
| _ => [index - 1, index + 1]
|
|
||||||
} |> Belt.Array.map(_, r => sortedArray[r])
|
|
||||||
let hasSimilarElement = Belt.Array.some(possiblySimilarElements, r => r == element)
|
|
||||||
hasSimilarElement
|
|
||||||
? FloatFloatMap.increment(element, discrete)
|
|
||||||
: {
|
|
||||||
let _ = Js.Array.push(element, continuous)
|
|
||||||
}
|
|
||||||
|
|
||||||
()
|
|
||||||
})
|
|
||||||
|
|
||||||
(continuous, discrete)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
This function works very similarly to splitContinuousAndDiscreteForDuplicates. The one major difference
|
|
||||||
is that you can specify a minDiscreteWeight. If the min discreet weight is 4, that would mean that
|
|
||||||
at least four elements needed from a specific value for that to be kept as discrete. This is important
|
|
||||||
because in some cases, we can expect that some common elements will be generated by regular operations.
|
|
||||||
The final continous array will be sorted.
|
|
||||||
*/
|
|
||||||
let splitContinuousAndDiscreteForMinWeight = (
|
|
||||||
sortedArray: array<float>,
|
|
||||||
~minDiscreteWeight: int,
|
|
||||||
) => {
|
|
||||||
let (continuous, discrete) = _splitContinuousAndDiscreteForDuplicates(sortedArray)
|
|
||||||
let keepFn = v => Belt.Float.toInt(v) >= minDiscreteWeight
|
|
||||||
let (discreteToKeep, discreteToIntegrate) = FloatFloatMap.partition(
|
|
||||||
((_, v)) => keepFn(v),
|
|
||||||
discrete,
|
|
||||||
)
|
|
||||||
let newContinousSamples =
|
|
||||||
discreteToIntegrate->FloatFloatMap.toArray
|
|
||||||
|> fmap(((k, v)) => Belt.Array.makeBy(Belt.Float.toInt(v), _ => k))
|
|
||||||
|> Belt.Array.concatMany
|
|
||||||
let newContinuous = concat(continuous, newContinousSamples)
|
|
||||||
newContinuous |> Array.fast_sort(floatCompare)
|
|
||||||
(newContinuous, discreteToKeep)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module Sorted = Floats.Sorted
|
|
||||||
}
|
|
||||||
|
|
||||||
module A2 = {
|
|
||||||
let fmap = (a, b) => A.fmap(b, a)
|
|
||||||
let fmapi = (a, b) => A.fmapi(b, a)
|
|
||||||
let joinWith = (a, b) => A.joinWith(b, a)
|
|
||||||
let filter = (a, b) => A.filter(b, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
module JsArray = {
|
|
||||||
let concatSomes = (optionals: Js.Array.t<option<'a>>): Js.Array.t<'a> =>
|
|
||||||
optionals
|
|
||||||
|> Js.Array.filter(O.isSome)
|
|
||||||
|> Js.Array.map(O.toExn("Warning: This should not have happened"))
|
|
||||||
let filter = Js.Array.filter
|
|
||||||
}
|
|
||||||
|
|
||||||
module Dict = {
|
|
||||||
type t<'a> = Js.Dict.t<'a>
|
|
||||||
let get = Js.Dict.get
|
|
||||||
let keys = Js.Dict.keys
|
|
||||||
let fromArray = Js.Dict.fromArray
|
|
||||||
let toArray = Js.Dict.entries
|
|
||||||
let concat = (a, b) => A.concat(toArray(a), toArray(b))->fromArray
|
|
||||||
let concatMany = ts => ts->A2.fmap(toArray)->A.concatMany->fromArray
|
|
||||||
}
|
|
||||||
|
|
360
packages/squiggle-lang/src/rescript/Utility/E/E_A.res
Normal file
360
packages/squiggle-lang/src/rescript/Utility/E/E_A.res
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
/* A for Array */
|
||||||
|
// module O = E_O
|
||||||
|
module Int = E_Int
|
||||||
|
module L = E_L
|
||||||
|
module FloatFloatMap = E_FloatFloatMap
|
||||||
|
|
||||||
|
let fmap = Array.map
|
||||||
|
let fmapi = Array.mapi
|
||||||
|
let to_list = Array.to_list
|
||||||
|
let of_list = Array.of_list
|
||||||
|
let length = Array.length
|
||||||
|
let append = Array.append
|
||||||
|
// let empty = [||];
|
||||||
|
let unsafe_get = Array.unsafe_get
|
||||||
|
let get = Belt.Array.get
|
||||||
|
let getBy = Belt.Array.getBy
|
||||||
|
let getIndexBy = Belt.Array.getIndexBy
|
||||||
|
let last = a => get(a, length(a) - 1)
|
||||||
|
let first = get(_, 0)
|
||||||
|
let hasBy = (r, fn) => Belt.Array.getBy(r, fn) |> E_O.isSome
|
||||||
|
let fold_left = Array.fold_left
|
||||||
|
let fold_right = Array.fold_right
|
||||||
|
let concat = Belt.Array.concat
|
||||||
|
let concatMany = Belt.Array.concatMany
|
||||||
|
let keepMap = Belt.Array.keepMap
|
||||||
|
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
|
||||||
|
let stableSortBy = Belt.SortArray.stableSortBy
|
||||||
|
let toNoneIfEmpty = r => isEmpty(r) ? None : Some(r)
|
||||||
|
let toRanges = (a: array<'a>) =>
|
||||||
|
switch a |> Belt.Array.length {
|
||||||
|
| 0
|
||||||
|
| 1 =>
|
||||||
|
Belt.Result.Error("Must be at least 2 elements")
|
||||||
|
| n =>
|
||||||
|
Belt.Array.makeBy(n - 1, r => r)
|
||||||
|
|> Belt.Array.map(_, index => (
|
||||||
|
Belt.Array.getUnsafe(a, index),
|
||||||
|
Belt.Array.getUnsafe(a, index + 1),
|
||||||
|
))
|
||||||
|
|> (x => Ok(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
let getByFmap = (a, fn, boolCondition) => {
|
||||||
|
let i = ref(0)
|
||||||
|
let finalFunctionValue = ref(None)
|
||||||
|
let length = Belt.Array.length(a)
|
||||||
|
|
||||||
|
while i.contents < length && finalFunctionValue.contents == None {
|
||||||
|
let itemWithFnApplied = Belt.Array.getUnsafe(a, i.contents) |> fn
|
||||||
|
if boolCondition(itemWithFnApplied) {
|
||||||
|
finalFunctionValue := Some(itemWithFnApplied)
|
||||||
|
}
|
||||||
|
i := i.contents + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
finalFunctionValue.contents
|
||||||
|
}
|
||||||
|
|
||||||
|
let tail = Belt.Array.sliceToEnd(_, 1)
|
||||||
|
|
||||||
|
let zip = Belt.Array.zip
|
||||||
|
let unzip = Belt.Array.unzip
|
||||||
|
let zip3 = (a, b, c) =>
|
||||||
|
Belt.Array.zip(a, b)->Belt.Array.zip(c)->Belt.Array.map((((v1, v2), v3)) => (v1, v2, v3))
|
||||||
|
// This zips while taking the longest elements of each array.
|
||||||
|
let zipMaxLength = (array1, array2) => {
|
||||||
|
let maxLength = Int.max(length(array1), length(array2))
|
||||||
|
let result = maxLength |> Belt.Array.makeUninitializedUnsafe
|
||||||
|
for i in 0 to maxLength - 1 {
|
||||||
|
Belt.Array.set(result, i, (get(array1, i), get(array2, i))) |> ignore
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
let asList = (f: list<'a> => list<'a>, r: array<'a>) => r |> to_list |> f |> of_list
|
||||||
|
/* TODO: Is there a better way of doing this? */
|
||||||
|
let uniq = r => asList(L.uniq, r)
|
||||||
|
|
||||||
|
//intersperse([1,2,3], [10,11,12]) => [1,10,2,11,3,12]
|
||||||
|
let intersperse = (a: array<'a>, b: array<'a>) => {
|
||||||
|
let items: ref<array<'a>> = ref([])
|
||||||
|
|
||||||
|
Belt.Array.forEachWithIndex(a, (i, item) =>
|
||||||
|
switch Belt.Array.get(b, i) {
|
||||||
|
| Some(r) => items := append(items.contents, [item, r])
|
||||||
|
| None => items := append(items.contents, [item])
|
||||||
|
}
|
||||||
|
)
|
||||||
|
items.contents
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is like map, but
|
||||||
|
//accumulate((a,b) => a + b, [1,2,3]) => [1, 3, 5]
|
||||||
|
let accumulate = (fn: ('a, 'a) => 'a, items: array<'a>) => {
|
||||||
|
let length = items |> length
|
||||||
|
let empty = Belt.Array.make(length, items |> unsafe_get(_, 0))
|
||||||
|
Belt.Array.forEachWithIndex(items, (index, element) => {
|
||||||
|
let item = switch index {
|
||||||
|
| 0 => element
|
||||||
|
| index => fn(element, unsafe_get(empty, index - 1))
|
||||||
|
}
|
||||||
|
let _ = Belt.Array.set(empty, index, item)
|
||||||
|
})
|
||||||
|
empty
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo: Is -1 still the indicator that this is false (as is true with
|
||||||
|
// @todo: js findIndex)? Wasn't sure.
|
||||||
|
let findIndex = (e, i) =>
|
||||||
|
Js.Array.findIndex(e, i) |> (
|
||||||
|
r =>
|
||||||
|
switch r {
|
||||||
|
| -1 => None
|
||||||
|
| r => Some(r)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
let filter = Js.Array.filter
|
||||||
|
let joinWith = Js.Array.joinWith
|
||||||
|
let transpose = (xs: array<array<'a>>): array<array<'a>> => {
|
||||||
|
let arr: array<array<'a>> = []
|
||||||
|
for i in 0 to length(xs) - 1 {
|
||||||
|
for j in 0 to length(xs[i]) - 1 {
|
||||||
|
if Js.Array.length(arr) <= j {
|
||||||
|
ignore(Js.Array.push([xs[i][j]], arr))
|
||||||
|
} else {
|
||||||
|
ignore(Js.Array.push(xs[i][j], arr[j]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr
|
||||||
|
}
|
||||||
|
|
||||||
|
let all = (p: 'a => bool, xs: array<'a>): bool => length(filter(p, xs)) == length(xs)
|
||||||
|
let any = (p: 'a => bool, xs: array<'a>): bool => length(filter(p, xs)) > 0
|
||||||
|
|
||||||
|
module O = {
|
||||||
|
let concatSomes = (optionals: array<option<'a>>): array<'a> =>
|
||||||
|
optionals
|
||||||
|
|> Js.Array.filter(E_O.isSome)
|
||||||
|
|> Js.Array.map(E_O.toExn("Warning: This should not have happened"))
|
||||||
|
let defaultEmpty = (o: option<array<'a>>): array<'a> =>
|
||||||
|
switch o {
|
||||||
|
| Some(o) => o
|
||||||
|
| None => []
|
||||||
|
}
|
||||||
|
// REturns `None` there are no non-`None` elements
|
||||||
|
let rec arrSomeToSomeArr = (optionals: array<option<'a>>): option<array<'a>> => {
|
||||||
|
let optionals' = optionals->Belt.List.fromArray
|
||||||
|
switch optionals' {
|
||||||
|
| list{} => []->Some
|
||||||
|
| list{x, ...xs} =>
|
||||||
|
switch x {
|
||||||
|
| Some(_) => xs->Belt.List.toArray->arrSomeToSomeArr
|
||||||
|
| None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let firstSome = x => Belt.Array.getBy(x, E_O.isSome)
|
||||||
|
|
||||||
|
let firstSomeFn = (r: array<unit => option<'a>>): option<'a> =>
|
||||||
|
E_O.flatten(getByFmap(r, l => l(), E_O.isSome))
|
||||||
|
|
||||||
|
let firstSomeFnWithDefault = (r, default) => firstSomeFn(r)->E_O2.default(default)
|
||||||
|
|
||||||
|
let openIfAllSome = (optionals: array<option<'a>>): option<array<'a>> => {
|
||||||
|
if all(E_O.isSome, optionals) {
|
||||||
|
Some(optionals |> fmap(E_O.toExn("Warning: This should not have happened")))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module R = {
|
||||||
|
let firstErrorOrOpen = (results: array<Belt.Result.t<'a, 'b>>): Belt.Result.t<array<'a>, 'b> => {
|
||||||
|
let bringErrorUp = switch results |> Belt.Array.getBy(_, Belt.Result.isError) {
|
||||||
|
| Some(Belt.Result.Error(err)) => Belt.Result.Error(err)
|
||||||
|
| Some(Belt.Result.Ok(_)) => Belt.Result.Ok(results)
|
||||||
|
| None => Belt.Result.Ok(results)
|
||||||
|
}
|
||||||
|
let forceOpen = (r: array<Belt.Result.t<'a, 'b>>): array<'a> =>
|
||||||
|
r |> Belt.Array.map(_, r => Belt.Result.getExn(r))
|
||||||
|
bringErrorUp |> Belt.Result.map(_, forceOpen)
|
||||||
|
}
|
||||||
|
let filterOk = (x: array<result<'a, 'b>>): array<'a> => fmap(E_R.toOption, x)->O.concatSomes
|
||||||
|
|
||||||
|
let forM = (x: array<'a>, fn: 'a => result<'b, 'c>): result<array<'b>, 'c> =>
|
||||||
|
firstErrorOrOpen(fmap(fn, x))
|
||||||
|
|
||||||
|
let foldM = (fn: ('c, 'a) => result<'b, 'e>, init: 'c, x: array<'a>): result<'c, 'e> => {
|
||||||
|
let acc = ref(init)
|
||||||
|
let final = ref(Ok())
|
||||||
|
let break = ref(false)
|
||||||
|
let i = ref(0)
|
||||||
|
|
||||||
|
while break.contents != true && i.contents < length(x) {
|
||||||
|
switch fn(acc.contents, x[i.contents]) {
|
||||||
|
| Ok(r) => acc := r
|
||||||
|
| Error(err) => {
|
||||||
|
final := Error(err)
|
||||||
|
break := true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i := i.contents + 1
|
||||||
|
}
|
||||||
|
switch final.contents {
|
||||||
|
| Ok(_) => Ok(acc.contents)
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module Floats = {
|
||||||
|
type t = array<float>
|
||||||
|
let mean = Jstat.mean
|
||||||
|
let geomean = Jstat.geomean
|
||||||
|
let mode = Jstat.mode
|
||||||
|
let variance = Jstat.variance
|
||||||
|
let stdev = Jstat.stdev
|
||||||
|
let sum = Jstat.sum
|
||||||
|
let product = Jstat.product
|
||||||
|
let random = Js.Math.random_int
|
||||||
|
|
||||||
|
let floatCompare: (float, float) => int = compare
|
||||||
|
let sort = t => {
|
||||||
|
let r = t
|
||||||
|
r |> Array.fast_sort(floatCompare)
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
let getNonFinite = (t: t) => Belt.Array.getBy(t, r => !Js.Float.isFinite(r))
|
||||||
|
let getBelowZero = (t: t) => Belt.Array.getBy(t, r => r < 0.0)
|
||||||
|
|
||||||
|
let isSorted = (t: t): bool =>
|
||||||
|
if Array.length(t) < 1 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
reduce(zip(t, tail(t)), true, (acc, (first, second)) => acc && first < second)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Passing true for the exclusive parameter excludes both endpoints of the range.
|
||||||
|
//https://jstat.github.io/all.html
|
||||||
|
let percentile = (a, b) => Jstat.percentile(a, b, false)
|
||||||
|
|
||||||
|
// Gives an array with all the differences between values
|
||||||
|
// diff([1,5,3,7]) = [4,-2,4]
|
||||||
|
let diff = (t: t): array<float> =>
|
||||||
|
Belt.Array.zipBy(t, Belt.Array.sliceToEnd(t, 1), (left, right) => right -. left)
|
||||||
|
|
||||||
|
let cumSum = (t: t): array<float> => accumulate((a, b) => a +. b, t)
|
||||||
|
let cumProd = (t: t): array<float> => accumulate((a, b) => a *. b, t)
|
||||||
|
|
||||||
|
exception RangeError(string)
|
||||||
|
let range = (min: float, max: float, n: int): array<float> =>
|
||||||
|
switch n {
|
||||||
|
| 0 => []
|
||||||
|
| 1 => [min]
|
||||||
|
| 2 => [min, max]
|
||||||
|
| _ if min == max => Belt.Array.make(n, min)
|
||||||
|
| _ if n < 0 => raise(RangeError("n must be greater than 0"))
|
||||||
|
| _ if min > max => raise(RangeError("Min value is less then max value"))
|
||||||
|
| _ =>
|
||||||
|
let diff = (max -. min) /. Belt.Float.fromInt(n - 1)
|
||||||
|
Belt.Array.makeBy(n, i => min +. Belt.Float.fromInt(i) *. diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
let min = Js.Math.minMany_float
|
||||||
|
let max = Js.Math.maxMany_float
|
||||||
|
|
||||||
|
module Sorted = {
|
||||||
|
let min = first
|
||||||
|
let max = last
|
||||||
|
let range = (~min=min, ~max=max, a) =>
|
||||||
|
switch (min(a), max(a)) {
|
||||||
|
| (Some(min), Some(max)) => Some(max -. min)
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
|
||||||
|
let binarySearchFirstElementGreaterIndex = (ar: array<'a>, el: 'a) => {
|
||||||
|
let el = Belt.SortArray.binarySearchBy(ar, el, floatCompare)
|
||||||
|
let el = el < 0 ? el * -1 - 1 : el
|
||||||
|
switch el {
|
||||||
|
| e if e >= length(ar) => #overMax
|
||||||
|
| e if e == 0 => #underMin
|
||||||
|
| e => #firstHigher(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let concat = (t1: array<'a>, t2: array<'a>) => Belt.Array.concat(t1, t2)->sort
|
||||||
|
|
||||||
|
let concatMany = (t1: array<array<'a>>) => Belt.Array.concatMany(t1)->sort
|
||||||
|
|
||||||
|
let makeIncrementalUp = (a, b) =>
|
||||||
|
Array.make(b - a + 1, a) |> Array.mapi((i, c) => c + i) |> Belt.Array.map(_, float_of_int)
|
||||||
|
|
||||||
|
let makeIncrementalDown = (a, b) =>
|
||||||
|
Array.make(a - b + 1, a) |> Array.mapi((i, c) => c - i) |> Belt.Array.map(_, float_of_int)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function goes through a sorted array and divides it into two different clusters:
|
||||||
|
continuous samples and discrete samples. The discrete samples are stored in a mutable map.
|
||||||
|
Samples are thought to be discrete if they have any duplicates.
|
||||||
|
*/
|
||||||
|
let _splitContinuousAndDiscreteForDuplicates = (sortedArray: array<float>) => {
|
||||||
|
let continuous: array<float> = []
|
||||||
|
let discrete = FloatFloatMap.empty()
|
||||||
|
Belt.Array.forEachWithIndex(sortedArray, (index, element) => {
|
||||||
|
let maxIndex = (sortedArray |> Array.length) - 1
|
||||||
|
let possiblySimilarElements = switch index {
|
||||||
|
| 0 => [index + 1]
|
||||||
|
| n if n == maxIndex => [index - 1]
|
||||||
|
| _ => [index - 1, index + 1]
|
||||||
|
} |> Belt.Array.map(_, r => sortedArray[r])
|
||||||
|
let hasSimilarElement = Belt.Array.some(possiblySimilarElements, r => r == element)
|
||||||
|
hasSimilarElement
|
||||||
|
? FloatFloatMap.increment(element, discrete)
|
||||||
|
: {
|
||||||
|
let _ = Js.Array.push(element, continuous)
|
||||||
|
}
|
||||||
|
|
||||||
|
()
|
||||||
|
})
|
||||||
|
|
||||||
|
(continuous, discrete)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function works very similarly to splitContinuousAndDiscreteForDuplicates. The one major difference
|
||||||
|
is that you can specify a minDiscreteWeight. If the min discreet weight is 4, that would mean that
|
||||||
|
at least four elements needed from a specific value for that to be kept as discrete. This is important
|
||||||
|
because in some cases, we can expect that some common elements will be generated by regular operations.
|
||||||
|
The final continous array will be sorted.
|
||||||
|
*/
|
||||||
|
let splitContinuousAndDiscreteForMinWeight = (
|
||||||
|
sortedArray: array<float>,
|
||||||
|
~minDiscreteWeight: int,
|
||||||
|
) => {
|
||||||
|
let (continuous, discrete) = _splitContinuousAndDiscreteForDuplicates(sortedArray)
|
||||||
|
let keepFn = v => Belt.Float.toInt(v) >= minDiscreteWeight
|
||||||
|
let (discreteToKeep, discreteToIntegrate) = FloatFloatMap.partition(
|
||||||
|
((_, v)) => keepFn(v),
|
||||||
|
discrete,
|
||||||
|
)
|
||||||
|
let newContinousSamples =
|
||||||
|
discreteToIntegrate->FloatFloatMap.toArray
|
||||||
|
|> fmap(((k, v)) => Belt.Array.makeBy(Belt.Float.toInt(v), _ => k))
|
||||||
|
|> Belt.Array.concatMany
|
||||||
|
let newContinuous = concat(continuous, newContinousSamples)
|
||||||
|
newContinuous |> Array.fast_sort(floatCompare)
|
||||||
|
(newContinuous, discreteToKeep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module Sorted = Floats.Sorted
|
5
packages/squiggle-lang/src/rescript/Utility/E/E_A2.res
Normal file
5
packages/squiggle-lang/src/rescript/Utility/E/E_A2.res
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module A = E_A
|
||||||
|
let fmap = (a, b) => A.fmap(b, a)
|
||||||
|
let fmapi = (a, b) => A.fmapi(b, a)
|
||||||
|
let joinWith = (a, b) => A.joinWith(b, a)
|
||||||
|
let filter = (a, b) => A.filter(b, a)
|
11
packages/squiggle-lang/src/rescript/Utility/E/E_B.res
Normal file
11
packages/squiggle-lang/src/rescript/Utility/E/E_B.res
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
type t = bool
|
||||||
|
let toString = (t: t) => t ? "TRUE" : "FALSE"
|
||||||
|
let fromString = str => str == "TRUE" ? true : false
|
||||||
|
|
||||||
|
module O = {
|
||||||
|
let toBool = opt =>
|
||||||
|
switch opt {
|
||||||
|
| Some(true) => true
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
}
|
10
packages/squiggle-lang/src/rescript/Utility/E/E_Dict.res
Normal file
10
packages/squiggle-lang/src/rescript/Utility/E/E_Dict.res
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
module A = E_A
|
||||||
|
module A2 = E_A2
|
||||||
|
|
||||||
|
type t<'a> = Js.Dict.t<'a>
|
||||||
|
let get = Js.Dict.get
|
||||||
|
let keys = Js.Dict.keys
|
||||||
|
let fromArray = Js.Dict.fromArray
|
||||||
|
let toArray = Js.Dict.entries
|
||||||
|
let concat = (a, b) => A.concat(toArray(a), toArray(b))->fromArray
|
||||||
|
let concatMany = ts => ts->A2.fmap(toArray)->A.concatMany->fromArray
|
20
packages/squiggle-lang/src/rescript/Utility/E/E_F.res
Normal file
20
packages/squiggle-lang/src/rescript/Utility/E/E_F.res
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/* Functions */
|
||||||
|
let pipe = (f, g, x) => g(f(x))
|
||||||
|
let compose = (f, g, x) => f(g(x))
|
||||||
|
let flip = (f, a, b) => f(b, a)
|
||||||
|
let always = (x, _y) => x
|
||||||
|
|
||||||
|
let apply = (a, e) => a |> e
|
||||||
|
|
||||||
|
let flatten2Callbacks = (fn1, fn2, fnlast) =>
|
||||||
|
fn1(response1 => fn2(response2 => fnlast(response1, response2)))
|
||||||
|
|
||||||
|
let flatten3Callbacks = (fn1, fn2, fn3, fnlast) =>
|
||||||
|
fn1(response1 => fn2(response2 => fn3(response3 => fnlast(response1, response2, response3))))
|
||||||
|
|
||||||
|
let flatten4Callbacks = (fn1, fn2, fn3, fn4, fnlast) =>
|
||||||
|
fn1(response1 =>
|
||||||
|
fn2(response2 =>
|
||||||
|
fn3(response3 => fn4(response4 => fnlast(response1, response2, response3, response4)))
|
||||||
|
)
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
let with2DigitsPrecision = Js.Float.toPrecisionWithPrecision(_, ~digits=2)
|
||||||
|
let with3DigitsPrecision = Js.Float.toPrecisionWithPrecision(_, ~digits=3)
|
||||||
|
let toFixed = Js.Float.toFixed
|
||||||
|
let toString = Js.Float.toString
|
||||||
|
let isFinite = Js.Float.isFinite
|
||||||
|
let toInt = Belt.Float.toInt
|
|
@ -0,0 +1,24 @@
|
||||||
|
module Id = Belt.Id.MakeComparable({
|
||||||
|
type t = float
|
||||||
|
let cmp: (float, float) => int = Pervasives.compare
|
||||||
|
})
|
||||||
|
|
||||||
|
type t = Belt.MutableMap.t<Id.t, float, Id.identity>
|
||||||
|
|
||||||
|
let fromArray = (ar: array<(float, float)>) => Belt.MutableMap.fromArray(ar, ~id=module(Id))
|
||||||
|
let toArray = (t: t): array<(float, float)> => Belt.MutableMap.toArray(t)
|
||||||
|
let empty = () => Belt.MutableMap.make(~id=module(Id))
|
||||||
|
let increment = (el, t: t) =>
|
||||||
|
Belt.MutableMap.update(t, el, x =>
|
||||||
|
switch x {
|
||||||
|
| Some(n) => Some(n +. 1.0)
|
||||||
|
| None => Some(1.0)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
let get = (el, t: t) => Belt.MutableMap.get(t, el)
|
||||||
|
let fmap = (fn, t: t) => Belt.MutableMap.map(t, fn)
|
||||||
|
let partition = (fn, t: t) => {
|
||||||
|
let (match, noMatch) = Belt.Array.partition(toArray(t), fn)
|
||||||
|
(fromArray(match), fromArray(noMatch))
|
||||||
|
}
|
4
packages/squiggle-lang/src/rescript/Utility/E/E_I.res
Normal file
4
packages/squiggle-lang/src/rescript/Utility/E/E_I.res
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
let increment = n => n + 1
|
||||||
|
let decrement = n => n - 1
|
||||||
|
let toString = Js.Int.toString
|
||||||
|
let toFloat = Js.Int.toFloat
|
2
packages/squiggle-lang/src/rescript/Utility/E/E_Int.res
Normal file
2
packages/squiggle-lang/src/rescript/Utility/E/E_Int.res
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
let max = (i1: int, i2: int) => i1 > i2 ? i1 : i2
|
||||||
|
let random = (~min, ~max) => Js.Math.random_int(min, max)
|
19
packages/squiggle-lang/src/rescript/Utility/E/E_J.res
Normal file
19
packages/squiggle-lang/src/rescript/Utility/E/E_J.res
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
module F = E_F
|
||||||
|
|
||||||
|
let toString = F.pipe(Js.Json.decodeString, E_O.default(""))
|
||||||
|
let fromString = Js.Json.string
|
||||||
|
let fromNumber = Js.Json.number
|
||||||
|
|
||||||
|
module O = {
|
||||||
|
let fromString = (str: string) =>
|
||||||
|
switch str {
|
||||||
|
| "" => None
|
||||||
|
| _ => Some(Js.Json.string(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
let toString = (str: option<'a>) =>
|
||||||
|
switch str {
|
||||||
|
| Some(str) => Some(str |> F.pipe(Js.Json.decodeString, E_O.default("")))
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
module O = E_O
|
||||||
|
let concatSomes = (optionals: Js.Array.t<option<'a>>): Js.Array.t<'a> =>
|
||||||
|
optionals
|
||||||
|
|> Js.Array.filter(O.isSome)
|
||||||
|
|> Js.Array.map(O.toExn("Warning: This should not have happened"))
|
||||||
|
let filter = Js.Array.filter
|
|
@ -0,0 +1,4 @@
|
||||||
|
let fromString = Js.Date.fromString
|
||||||
|
let now = Js.Date.now
|
||||||
|
let make = Js.Date.make
|
||||||
|
let valueOf = Js.Date.valueOf
|
151
packages/squiggle-lang/src/rescript/Utility/E/E_L.res
Normal file
151
packages/squiggle-lang/src/rescript/Utility/E/E_L.res
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
/* List */
|
||||||
|
module F = E_F
|
||||||
|
module O = E_O
|
||||||
|
|
||||||
|
module Util = {
|
||||||
|
let eq = \"=="
|
||||||
|
}
|
||||||
|
let fmap = List.map
|
||||||
|
let get = Belt.List.get
|
||||||
|
let toArray = Array.of_list
|
||||||
|
let fmapi = List.mapi
|
||||||
|
let concat = List.concat
|
||||||
|
let concat' = (xs, ys) => List.append(ys, xs)
|
||||||
|
|
||||||
|
let rec drop = (i, xs) =>
|
||||||
|
switch (i, xs) {
|
||||||
|
| (_, list{}) => list{}
|
||||||
|
| (i, _) if i <= 0 => xs
|
||||||
|
| (i, list{_, ...b}) => drop(i - 1, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
let append = (a, xs) => List.append(xs, list{a})
|
||||||
|
let take = {
|
||||||
|
let rec loop = (i, xs, acc) =>
|
||||||
|
switch (i, xs) {
|
||||||
|
| (i, _) if i <= 0 => acc
|
||||||
|
| (_, list{}) => acc
|
||||||
|
| (i, list{a, ...b}) => loop(i - 1, b, append(a, acc))
|
||||||
|
}
|
||||||
|
(i, xs) => loop(i, xs, list{})
|
||||||
|
}
|
||||||
|
let takeLast = (i, xs) => List.rev(xs) |> take(i) |> List.rev
|
||||||
|
|
||||||
|
let splitAt = (i, xs) => (take(i, xs), takeLast(List.length(xs) - i, xs))
|
||||||
|
let remove = (i, n, xs) => {
|
||||||
|
let (a, b) = splitAt(i, xs)
|
||||||
|
\"@"(a, drop(n, b))
|
||||||
|
}
|
||||||
|
|
||||||
|
let find = List.find
|
||||||
|
let filter = List.filter
|
||||||
|
let for_all = List.for_all
|
||||||
|
let exists = List.exists
|
||||||
|
let sort = List.sort
|
||||||
|
let length = List.length
|
||||||
|
|
||||||
|
let filter_opt = xs => {
|
||||||
|
let rec loop = (l, acc) =>
|
||||||
|
switch l {
|
||||||
|
| list{} => acc
|
||||||
|
| list{hd, ...tl} =>
|
||||||
|
switch hd {
|
||||||
|
| None => loop(tl, acc)
|
||||||
|
| Some(x) => loop(tl, list{x, ...acc})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List.rev(loop(xs, list{}))
|
||||||
|
}
|
||||||
|
|
||||||
|
let containsWith = f => List.exists(f)
|
||||||
|
|
||||||
|
let uniqWithBy = (eq, f, xs) =>
|
||||||
|
List.fold_left(
|
||||||
|
((acc, tacc), v) =>
|
||||||
|
containsWith(eq(f(v)), tacc) ? (acc, tacc) : (append(v, acc), append(f(v), tacc)),
|
||||||
|
(list{}, list{}),
|
||||||
|
xs,
|
||||||
|
) |> fst
|
||||||
|
|
||||||
|
let uniqBy = (f, xs) => uniqWithBy(Util.eq, f, xs)
|
||||||
|
let join = j => List.fold_left((acc, v) => String.length(acc) == 0 ? v : acc ++ (j ++ v), "")
|
||||||
|
|
||||||
|
let head = xs =>
|
||||||
|
switch List.hd(xs) {
|
||||||
|
| exception _ => None
|
||||||
|
| a => Some(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
let uniq = xs => uniqBy(x => x, xs)
|
||||||
|
let flatten = List.flatten
|
||||||
|
let last = xs => xs |> List.rev |> head
|
||||||
|
let append = List.append
|
||||||
|
let getBy = Belt.List.getBy
|
||||||
|
let dropLast = (i, xs) => take(List.length(xs) - i, xs)
|
||||||
|
let containsWith = f => List.exists(f)
|
||||||
|
let contains = x => containsWith(Util.eq(x))
|
||||||
|
|
||||||
|
let reject = pred => List.filter(x => !pred(x))
|
||||||
|
let tail = xs =>
|
||||||
|
switch List.tl(xs) {
|
||||||
|
| exception _ => None
|
||||||
|
| a => Some(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
let init = xs => {
|
||||||
|
O.fmap(List.rev, xs |> List.rev |> tail)
|
||||||
|
}
|
||||||
|
|
||||||
|
let singleton = (x: 'a): list<'a> => list{x}
|
||||||
|
|
||||||
|
let adjust = (f, i, xs) => {
|
||||||
|
let (a, b) = splitAt(i + 1, xs)
|
||||||
|
switch a {
|
||||||
|
| _ if i < 0 => xs
|
||||||
|
| _ if i >= List.length(xs) => xs
|
||||||
|
| list{} => b
|
||||||
|
| list{a} => list{f(a), ...b}
|
||||||
|
| a =>
|
||||||
|
O.fmap(
|
||||||
|
concat'(b),
|
||||||
|
O.bind(init(a), x => O.fmap(F.flip(append, x), O.fmap(fmap(f), O.fmap(singleton, last(a))))),
|
||||||
|
) |> O.default(xs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let without = (exclude, xs) => reject(x => contains(x, exclude), xs)
|
||||||
|
let update = (x, i, xs) => adjust(F.always(x), i, xs)
|
||||||
|
let iter = List.iter
|
||||||
|
|
||||||
|
let findIndex = {
|
||||||
|
let rec loop = (pred, xs, i) =>
|
||||||
|
switch xs {
|
||||||
|
| list{} => None
|
||||||
|
| list{a, ...b} => pred(a) ? Some(i) : loop(pred, b, i + 1)
|
||||||
|
}
|
||||||
|
(pred, xs) => loop(pred, xs, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
let headSafe = Belt.List.head
|
||||||
|
let tailSafe = Belt.List.tail
|
||||||
|
let headExn = Belt.List.headExn
|
||||||
|
let tailExn = Belt.List.tailExn
|
||||||
|
let zip = Belt.List.zip
|
||||||
|
|
||||||
|
let combinations2: list<'a> => list<('a, 'a)> = xs => {
|
||||||
|
let rec loop: ('a, list<'a>) => list<('a, 'a)> = (x', xs') => {
|
||||||
|
let n = length(xs')
|
||||||
|
if n == 0 {
|
||||||
|
list{}
|
||||||
|
} else {
|
||||||
|
let combs = fmap(y => (x', y), xs')
|
||||||
|
let hd = headExn(xs')
|
||||||
|
let tl = tailExn(xs')
|
||||||
|
concat(list{combs, loop(hd, tl)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (headSafe(xs), tailSafe(xs)) {
|
||||||
|
| (Some(x'), Some(xs')) => loop(x', xs')
|
||||||
|
| (_, _) => list{}
|
||||||
|
}
|
||||||
|
}
|
99
packages/squiggle-lang/src/rescript/Utility/E/E_O.res
Normal file
99
packages/squiggle-lang/src/rescript/Utility/E/E_O.res
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
let dimap = (sFn, rFn, e) =>
|
||||||
|
switch e {
|
||||||
|
| Some(r) => sFn(r)
|
||||||
|
| None => rFn()
|
||||||
|
}
|
||||||
|
()
|
||||||
|
let fmap = (f: 'a => 'b, x: option<'a>): option<'b> => {
|
||||||
|
switch x {
|
||||||
|
| None => None
|
||||||
|
| Some(x') => Some(f(x'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let bind = (o, f) =>
|
||||||
|
switch o {
|
||||||
|
| None => None
|
||||||
|
| Some(a) => f(a)
|
||||||
|
}
|
||||||
|
let default = (d, o) =>
|
||||||
|
switch o {
|
||||||
|
| None => d
|
||||||
|
| Some(a) => a
|
||||||
|
}
|
||||||
|
let defaultFn = (d, o) =>
|
||||||
|
switch o {
|
||||||
|
| None => d()
|
||||||
|
| Some(a) => a
|
||||||
|
}
|
||||||
|
let isSome = o =>
|
||||||
|
switch o {
|
||||||
|
| Some(_) => true
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
let isNone = o =>
|
||||||
|
switch o {
|
||||||
|
| None => true
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
let toExn = (err, o) =>
|
||||||
|
switch o {
|
||||||
|
| None => raise(Failure(err))
|
||||||
|
| Some(a) => a
|
||||||
|
}
|
||||||
|
|
||||||
|
let some = a => Some(a)
|
||||||
|
let firstSome = (a, b) =>
|
||||||
|
switch a {
|
||||||
|
| None => b
|
||||||
|
| _ => a
|
||||||
|
}
|
||||||
|
|
||||||
|
let toExt = toExn
|
||||||
|
|
||||||
|
let flatten = o =>
|
||||||
|
switch o {
|
||||||
|
| None => None
|
||||||
|
| Some(x) => x
|
||||||
|
}
|
||||||
|
|
||||||
|
let apply = (o, a) =>
|
||||||
|
switch o {
|
||||||
|
| Some(f) => bind(a, b => some(f(b)))
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
let flatApply = (fn, b) => apply(fn, Some(b)) |> flatten
|
||||||
|
|
||||||
|
let toBool = opt =>
|
||||||
|
switch opt {
|
||||||
|
| Some(_) => true
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
|
||||||
|
let ffmap = (fn, r) =>
|
||||||
|
switch r {
|
||||||
|
| Some(sm) => fn(sm)
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
|
||||||
|
let toString = opt =>
|
||||||
|
switch opt {
|
||||||
|
| Some(s) => s
|
||||||
|
| _ => ""
|
||||||
|
}
|
||||||
|
|
||||||
|
let toResult = (error, e) =>
|
||||||
|
switch e {
|
||||||
|
| Some(r) => Belt.Result.Ok(r)
|
||||||
|
| None => Error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
let compare = (compare, f1: option<float>, f2: option<float>) =>
|
||||||
|
switch (f1, f2) {
|
||||||
|
| (Some(f1), Some(f2)) => Some(compare(f1, f2) ? f1 : f2)
|
||||||
|
| (Some(f1), None) => Some(f1)
|
||||||
|
| (None, Some(f2)) => Some(f2)
|
||||||
|
| (None, None) => None
|
||||||
|
}
|
||||||
|
|
||||||
|
let min = compare(\"<")
|
||||||
|
let max = compare(\">")
|
7
packages/squiggle-lang/src/rescript/Utility/E/E_O2.res
Normal file
7
packages/squiggle-lang/src/rescript/Utility/E/E_O2.res
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module O = E_O
|
||||||
|
let default = (a, b) => O.default(b, a)
|
||||||
|
let defaultFn = (a, b) => O.defaultFn(b, a)
|
||||||
|
let toExn = (a, b) => O.toExn(b, a)
|
||||||
|
let fmap = (a, b) => O.fmap(b, a)
|
||||||
|
let toResult = (a, b) => O.toResult(b, a)
|
||||||
|
let bind = (a, b) => O.bind(b, a)
|
94
packages/squiggle-lang/src/rescript/Utility/E/E_R.res
Normal file
94
packages/squiggle-lang/src/rescript/Utility/E/E_R.res
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/* R for Result */
|
||||||
|
|
||||||
|
exception Assertion(string)
|
||||||
|
module U = E_U
|
||||||
|
|
||||||
|
open Belt.Result
|
||||||
|
let result = (okF, errF, r) =>
|
||||||
|
switch r {
|
||||||
|
| Ok(a) => okF(a)
|
||||||
|
| Error(err) => errF(err)
|
||||||
|
}
|
||||||
|
let id = e => e |> result(U.id, U.id)
|
||||||
|
let isOk = Belt.Result.isOk
|
||||||
|
let getError = (r: result<'a, 'b>) =>
|
||||||
|
switch r {
|
||||||
|
| Ok(_) => None
|
||||||
|
| Error(e) => Some(e)
|
||||||
|
}
|
||||||
|
let fmap = (f: 'a => 'b, r: result<'a, 'c>): result<'b, 'c> => {
|
||||||
|
switch r {
|
||||||
|
| Ok(r') => Ok(f(r'))
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let bind = (r, f) =>
|
||||||
|
switch r {
|
||||||
|
| Ok(a) => f(a)
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
}
|
||||||
|
let toExn = (msg: string, x: result<'a, 'b>): 'a =>
|
||||||
|
switch x {
|
||||||
|
| Ok(r) => r
|
||||||
|
| Error(_) => raise(Assertion(msg))
|
||||||
|
}
|
||||||
|
let toExnFnString = (errorToStringFn, o) =>
|
||||||
|
switch o {
|
||||||
|
| Ok(r) => r
|
||||||
|
| Error(r) => raise(Assertion(errorToStringFn(r)))
|
||||||
|
}
|
||||||
|
let default = (default, res: Belt.Result.t<'a, 'b>) =>
|
||||||
|
switch res {
|
||||||
|
| Ok(r) => r
|
||||||
|
| Error(_) => default
|
||||||
|
}
|
||||||
|
let merge = (a, b) =>
|
||||||
|
switch (a, b) {
|
||||||
|
| (Error(e), _) => Error(e)
|
||||||
|
| (_, Error(e)) => Error(e)
|
||||||
|
| (Ok(a), Ok(b)) => Ok((a, b))
|
||||||
|
}
|
||||||
|
let toOption = (e: Belt.Result.t<'a, 'b>) =>
|
||||||
|
switch e {
|
||||||
|
| Ok(r) => Some(r)
|
||||||
|
| Error(_) => None
|
||||||
|
}
|
||||||
|
|
||||||
|
let errorIfCondition = (errorCondition, errorMessage, r) =>
|
||||||
|
errorCondition(r) ? Error(errorMessage) : Ok(r)
|
||||||
|
|
||||||
|
let ap = (r, a) =>
|
||||||
|
switch r {
|
||||||
|
| Ok(f) => Ok(f(a))
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
}
|
||||||
|
let ap' = (r, a) =>
|
||||||
|
switch r {
|
||||||
|
| Ok(f) => fmap(f, a)
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
let liftM2: (('a, 'b) => 'c, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (op, xR, yR) => {
|
||||||
|
ap'(fmap(op, xR), yR)
|
||||||
|
}
|
||||||
|
|
||||||
|
let liftJoin2: (('a, 'b) => result<'c, 'd>, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (
|
||||||
|
op,
|
||||||
|
xR,
|
||||||
|
yR,
|
||||||
|
) => {
|
||||||
|
bind(liftM2(op, xR, yR), x => x)
|
||||||
|
}
|
||||||
|
|
||||||
|
let fmap2 = (f, r) =>
|
||||||
|
switch r {
|
||||||
|
| Ok(r) => r->Ok
|
||||||
|
| Error(x) => x->f->Error
|
||||||
|
}
|
||||||
|
|
||||||
|
//I'm not sure what to call this.
|
||||||
|
let unify = (a: result<'a, 'b>, c: 'b => 'a): 'a =>
|
||||||
|
switch a {
|
||||||
|
| Ok(x) => x
|
||||||
|
| Error(x) => c(x)
|
||||||
|
}
|
19
packages/squiggle-lang/src/rescript/Utility/E/E_R2.res
Normal file
19
packages/squiggle-lang/src/rescript/Utility/E/E_R2.res
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
module R = E_R
|
||||||
|
|
||||||
|
let fmap = (a, b) => R.fmap(b, a)
|
||||||
|
let bind = (a, b) => R.bind(b, a)
|
||||||
|
|
||||||
|
//Converts result type to change error type only
|
||||||
|
let errMap = (a: result<'a, 'b>, map: 'b => 'c): result<'a, 'c> =>
|
||||||
|
switch a {
|
||||||
|
| Ok(r) => Ok(r)
|
||||||
|
| Error(e) => Error(map(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
let fmap2 = (xR, f) =>
|
||||||
|
switch xR {
|
||||||
|
| Ok(x) => x->Ok
|
||||||
|
| Error(x) => x->f->Error
|
||||||
|
}
|
||||||
|
|
||||||
|
let toExn = (a, b) => R.toExn(b, a)
|
8
packages/squiggle-lang/src/rescript/Utility/E/E_S.res
Normal file
8
packages/squiggle-lang/src/rescript/Utility/E/E_S.res
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
let safe_fn_of_string = (fn, s: string): option<'a> =>
|
||||||
|
try Some(fn(s)) catch {
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
|
||||||
|
let safe_float = float_of_string->safe_fn_of_string
|
||||||
|
let safe_int = int_of_string->safe_fn_of_string
|
||||||
|
let default = (defaultStr, str) => str == "" ? defaultStr : str
|
|
@ -0,0 +1,9 @@
|
||||||
|
let first = (v: ('a, 'b)) => {
|
||||||
|
let (a, _) = v
|
||||||
|
a
|
||||||
|
}
|
||||||
|
let second = (v: ('a, 'b)) => {
|
||||||
|
let (_, b) = v
|
||||||
|
b
|
||||||
|
}
|
||||||
|
let toFnCall = (fn, (a1, a2)) => fn(a1, a2)
|
|
@ -0,0 +1 @@
|
||||||
|
let toFnCall = (fn, (a1, a2, a3)) => fn(a1, a2, a3)
|
4
packages/squiggle-lang/src/rescript/Utility/E/E_U.res
Normal file
4
packages/squiggle-lang/src/rescript/Utility/E/E_U.res
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/* Utils */
|
||||||
|
let isEqual = \"=="
|
||||||
|
let toA = a => [a]
|
||||||
|
let id = e => e
|
|
@ -3,7 +3,7 @@
|
||||||
"displayName": "Squiggle",
|
"displayName": "Squiggle",
|
||||||
"description": "Squiggle language support",
|
"description": "Squiggle language support",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"publisher": "QURI",
|
"publisher": "QURI",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -131,7 +131,7 @@
|
||||||
"@types/vscode": "^1.70.0",
|
"@types/vscode": "^1.70.0",
|
||||||
"glob": "^8.0.3",
|
"glob": "^8.0.3",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"typescript": "^4.8.2",
|
"typescript": "^4.8.3",
|
||||||
"vsce-yarn-patch": "^1.66.2"
|
"vsce-yarn-patch": "^1.66.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -14,9 +14,9 @@ Danger.laplace: (number, number) => number
|
||||||
Calculates the probability implied by [Laplace's rule of succession](https://en.wikipedia.org/wiki/Rule_of_succession)
|
Calculates the probability implied by [Laplace's rule of succession](https://en.wikipedia.org/wiki/Rule_of_succession)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
trials = 10
|
trials = 10;
|
||||||
successes = 1
|
successes = 1;
|
||||||
Danger.laplace(trials, successes) // (successes + 1) / (trials + 2) = 2 / 12 = 0.1666
|
Danger.laplace(trials, successes); // (successes + 1) / (trials + 2) = 2 / 12 = 0.1666
|
||||||
```
|
```
|
||||||
|
|
||||||
### factorial
|
### factorial
|
||||||
|
|
98
yarn.lock
98
yarn.lock
|
@ -1490,14 +1490,7 @@
|
||||||
core-js-pure "^3.20.2"
|
core-js-pure "^3.20.2"
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.9", "@babel/runtime@^7.5.0", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.6", "@babel/runtime@^7.18.9", "@babel/runtime@^7.19.0", "@babel/runtime@^7.5.0", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
||||||
version "7.18.9"
|
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
|
|
||||||
integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==
|
|
||||||
dependencies:
|
|
||||||
regenerator-runtime "^0.13.4"
|
|
||||||
|
|
||||||
"@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.18.6":
|
|
||||||
version "7.19.0"
|
version "7.19.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
|
||||||
integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
|
integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
|
||||||
|
@ -2210,10 +2203,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.6.tgz#35dd26987228b39ef2316db3b1245c42eb19e324"
|
resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.6.tgz#35dd26987228b39ef2316db3b1245c42eb19e324"
|
||||||
integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==
|
integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==
|
||||||
|
|
||||||
"@hookform/resolvers@^2.9.7":
|
"@hookform/resolvers@^2.9.8":
|
||||||
version "2.9.7"
|
version "2.9.8"
|
||||||
resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.9.7.tgz#8b257ae67234ce0270e6b044c1a61fb98ec02b4b"
|
resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.9.8.tgz#9af51d15602f3c6e3249714712d8275564e65b72"
|
||||||
integrity sha512-BloehX3MOLwuFEwT4yZnmolPjVmqyn8VsSuodLfazbCIqxBHsQ4qUZsi+bvNNCduRli1AGWFrkDLGD5QoNzsoA==
|
integrity sha512-iVVjH0USq+1TqDdGkWe2M1x7Wn5OFPgVRo7CbWFsXTqqXqCaZtZcnzJu+UhljCWbthFWxWGXKLGYUDPZ04oVvQ==
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.10.4":
|
"@humanwhocodes/config-array@^0.10.4":
|
||||||
version "0.10.4"
|
version "0.10.4"
|
||||||
|
@ -4676,10 +4669,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/katex/-/katex-0.11.1.tgz#34de04477dcf79e2ef6c8d23b41a3d81f9ebeaf5"
|
resolved "https://registry.yarnpkg.com/@types/katex/-/katex-0.11.1.tgz#34de04477dcf79e2ef6c8d23b41a3d81f9ebeaf5"
|
||||||
integrity sha512-DUlIj2nk0YnJdlWgsFuVKcX27MLW0KbKmGVoUHmFr+74FYYNUDAaj9ZqTADvsbE8rfxuVmSFc7KczYn5Y09ozg==
|
integrity sha512-DUlIj2nk0YnJdlWgsFuVKcX27MLW0KbKmGVoUHmFr+74FYYNUDAaj9ZqTADvsbE8rfxuVmSFc7KczYn5Y09ozg==
|
||||||
|
|
||||||
"@types/lodash@^4.14.167", "@types/lodash@^4.14.175", "@types/lodash@^4.14.184":
|
"@types/lodash@^4.14.167", "@types/lodash@^4.14.175", "@types/lodash@^4.14.185":
|
||||||
version "4.14.184"
|
version "4.14.185"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.184.tgz#23f96cd2a21a28e106dc24d825d4aa966de7a9fe"
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.185.tgz#c9843f5a40703a8f5edfd53358a58ae729816908"
|
||||||
integrity sha512-RoZphVtHbxPZizt4IcILciSWiC6dcn+eZ8oX9IWEYfDMcocdd42f7NPI6fQj+6zI8y4E0L7gu2pcZKLGTRaV9Q==
|
integrity sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA==
|
||||||
|
|
||||||
"@types/mdast@^3.0.0":
|
"@types/mdast@^3.0.0":
|
||||||
version "3.0.10"
|
version "3.0.10"
|
||||||
|
@ -4706,10 +4699,10 @@
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
form-data "^3.0.0"
|
form-data "^3.0.0"
|
||||||
|
|
||||||
"@types/node@*", "@types/node@18.x", "@types/node@^18.7.15":
|
"@types/node@*", "@types/node@18.x", "@types/node@^18.7.16":
|
||||||
version "18.7.15"
|
version "18.7.16"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.15.tgz#20ae1ec80c57ee844b469f968a1cd511d4088b29"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.16.tgz#0eb3cce1e37c79619943d2fd903919fc30850601"
|
||||||
integrity sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==
|
integrity sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg==
|
||||||
|
|
||||||
"@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0":
|
"@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0":
|
||||||
version "16.11.56"
|
version "16.11.56"
|
||||||
|
@ -4805,9 +4798,9 @@
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react@*", "@types/react@^18.0.1", "@types/react@^18.0.18":
|
"@types/react@*", "@types/react@^18.0.1", "@types/react@^18.0.18":
|
||||||
version "18.0.18"
|
version "18.0.19"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.18.tgz#9f16f33d57bc5d9dca848d12c3572110ff9429ac"
|
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.19.tgz#269a5f35b9a73c69dfb0c7189017013ab02acbaa"
|
||||||
integrity sha512-6hI08umYs6NaiHFEEGioXnxJ+oEhY3eRz8VCUaudZmGdtvPviCJB8mgaMxaDWAdPSYd4eFavrPk2QIolwbLYrg==
|
integrity sha512-BDc3Q+4Q3zsn7k9xZrKfjWyJsSlEDMs38gD1qp2eDazLCdcPqAT+vq1ND+Z8AGel/UiwzNUk8ptpywgNQcJ1MQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/prop-types" "*"
|
"@types/prop-types" "*"
|
||||||
"@types/scheduler" "*"
|
"@types/scheduler" "*"
|
||||||
|
@ -9158,10 +9151,10 @@ fast-check@^2.17.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
pure-rand "^5.0.1"
|
pure-rand "^5.0.1"
|
||||||
|
|
||||||
fast-check@^3.1.2:
|
fast-check@^3.1.3:
|
||||||
version "3.1.2"
|
version "3.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.1.2.tgz#1b09c3d856d425e06be9d39e9e23d1f6fa4a6d0e"
|
resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.1.3.tgz#134e5852e3c56b65e47a48b1a5022bee14c10ba3"
|
||||||
integrity sha512-OZRPFXhZHpIhtG46XtAMzVW1jtuR7Clw13wOcfw1v//tNnPCvVuLLlT1bEqywCQXNXR4qGT3tk7z0MUMSTit3Q==
|
integrity sha512-IFY7xJrOUktiC1ZnaJdrinaRpFgDZtURRPwzAiOhL8eyt2NbBTHNF1CO7vZUla1BoUeJVI7gLnTQA+Lko0T2dQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
pure-rand "^5.0.1"
|
pure-rand "^5.0.1"
|
||||||
|
|
||||||
|
@ -9529,10 +9522,10 @@ fragment-cache@^0.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
map-cache "^0.2.2"
|
map-cache "^0.2.2"
|
||||||
|
|
||||||
framer-motion@^7.2.1:
|
framer-motion@^7.3.2:
|
||||||
version "7.2.1"
|
version "7.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-7.2.1.tgz#0db5992ece791cb58357787ef9c29dd76281720d"
|
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-7.3.2.tgz#9768092cd98cf0ebaf70864f1248f2e703305a15"
|
||||||
integrity sha512-bt2ZqqGpPsW6UojYUa5poWQJu3sDr4Dp3IZsdVBYdKUJ8p+9PxOk1fYRAT8lTGGmaC5HFoKrbDXQeKWGAKZz9g==
|
integrity sha512-BTG0BqJSwxoFBWpwaaxS/954DGZFsluF+dUv9Hfq53VNkwUt5g+wYTEM66oTUhiH/+6R/y0Rq+BmkUBcmzbyMQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@motionone/dom" "10.13.1"
|
"@motionone/dom" "10.13.1"
|
||||||
framesync "6.1.2"
|
framesync "6.1.2"
|
||||||
|
@ -12353,12 +12346,12 @@ markdown-it@^8.3.1:
|
||||||
mdurl "^1.0.1"
|
mdurl "^1.0.1"
|
||||||
uc.micro "^1.0.5"
|
uc.micro "^1.0.5"
|
||||||
|
|
||||||
mathjs@^11.0.1, mathjs@^11.1.0:
|
mathjs@^11.0.1, mathjs@^11.2.0:
|
||||||
version "11.1.0"
|
version "11.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-11.1.0.tgz#501fc1b8d66155442ce7762bf04469168d38587c"
|
resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-11.2.0.tgz#06ade7425287bf69c3210158853996a55861e07e"
|
||||||
integrity sha512-cbsEruLNoIlj5h5vOF+DUQVe4EsA/WNomSQDMnX2WafX9TLneBSCRMx2okgGnSLzLoMGWQ211KVzY55bEnQa8Q==
|
integrity sha512-4x1LUP1tkNWWvaZiPO+rF9rKE5q4o541FF4m8ZIk1PlmSyHDGRAKutjA67rICK4DXWEY1gpumPOvaq3xuQHT6Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.18.9"
|
"@babel/runtime" "^7.19.0"
|
||||||
complex.js "^2.1.1"
|
complex.js "^2.1.1"
|
||||||
decimal.js "^10.4.0"
|
decimal.js "^10.4.0"
|
||||||
escape-latex "^1.2.0"
|
escape-latex "^1.2.0"
|
||||||
|
@ -13980,6 +13973,15 @@ postcss-import@^14.1.0:
|
||||||
read-cache "^1.0.0"
|
read-cache "^1.0.0"
|
||||||
resolve "^1.1.7"
|
resolve "^1.1.7"
|
||||||
|
|
||||||
|
postcss-import@^15.0.0:
|
||||||
|
version "15.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.0.0.tgz#0b66c25fdd9c0d19576e63c803cf39e4bad08822"
|
||||||
|
integrity sha512-Y20shPQ07RitgBGv2zvkEAu9bqvrD77C9axhj/aA1BQj4czape2MdClCExvB27EwYEJdGgKZBpKanb0t1rK2Kg==
|
||||||
|
dependencies:
|
||||||
|
postcss-value-parser "^4.0.0"
|
||||||
|
read-cache "^1.0.0"
|
||||||
|
resolve "^1.1.7"
|
||||||
|
|
||||||
postcss-initial@^4.0.1:
|
postcss-initial@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-4.0.1.tgz#529f735f72c5724a0fb30527df6fb7ac54d7de42"
|
resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-4.0.1.tgz#529f735f72c5724a0fb30527df6fb7ac54d7de42"
|
||||||
|
@ -14959,10 +14961,10 @@ react-helmet-async@*, react-helmet-async@^1.3.0:
|
||||||
react-fast-compare "^3.2.0"
|
react-fast-compare "^3.2.0"
|
||||||
shallowequal "^1.1.0"
|
shallowequal "^1.1.0"
|
||||||
|
|
||||||
react-hook-form@^7.34.2:
|
react-hook-form@^7.35.0:
|
||||||
version "7.34.2"
|
version "7.35.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.34.2.tgz#9ac6d1a309a7c4aaa369d1269357a70e9e9bf4de"
|
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.35.0.tgz#b133de48fc84b1e62f9277ba79dfbacd9bb13dd3"
|
||||||
integrity sha512-1lYWbEqr0GW7HHUjMScXMidGvV0BE2RJV3ap2BL7G0EJirkqpccTaawbsvBO8GZaB3JjCeFBEbnEWI1P8ZoLRQ==
|
integrity sha512-9CYdOed+Itbiu5VMVxW0PK9mBR3f0gDGJcZEyUSm0eJbDymQ913TRs2gHcQZZmfTC+rtxyDFRuelMxx/+xwMcw==
|
||||||
|
|
||||||
react-inspector@^5.1.0:
|
react-inspector@^5.1.0:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
|
@ -17433,10 +17435,10 @@ typedarray@^0.0.6:
|
||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
||||||
|
|
||||||
typescript@^4.8.2:
|
typescript@^4.8.3:
|
||||||
version "4.8.2"
|
version "4.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.3.tgz#d59344522c4bc464a65a730ac695007fdb66dd88"
|
||||||
integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==
|
integrity sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==
|
||||||
|
|
||||||
ua-parser-js@^0.7.30:
|
ua-parser-js@^0.7.30:
|
||||||
version "0.7.31"
|
version "0.7.31"
|
||||||
|
@ -18505,10 +18507,10 @@ webpack-dev-middleware@^5.3.1:
|
||||||
range-parser "^1.2.1"
|
range-parser "^1.2.1"
|
||||||
schema-utils "^4.0.0"
|
schema-utils "^4.0.0"
|
||||||
|
|
||||||
webpack-dev-server@^4.10.0, webpack-dev-server@^4.6.0, webpack-dev-server@^4.9.3:
|
webpack-dev-server@^4.11.0, webpack-dev-server@^4.6.0, webpack-dev-server@^4.9.3:
|
||||||
version "4.10.1"
|
version "4.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.10.1.tgz#124ac9ac261e75303d74d95ab6712b4aec3e12ed"
|
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.11.0.tgz#290ee594765cd8260adfe83b2d18115ea04484e7"
|
||||||
integrity sha512-FIzMq3jbBarz3ld9l7rbM7m6Rj1lOsgq/DyLGMX/fPEB1UBUPtf5iL/4eNfhx8YYJTRlzfv107UfWSWcBK5Odw==
|
integrity sha512-L5S4Q2zT57SK7tazgzjMiSMBdsw+rGYIX27MgPgx7LDhWO0lViPrHKoLS7jo5In06PWYAhlYu3PbyoC6yAThbw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/bonjour" "^3.5.9"
|
"@types/bonjour" "^3.5.9"
|
||||||
"@types/connect-history-api-fallback" "^1.3.5"
|
"@types/connect-history-api-fallback" "^1.3.5"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user