Merge pull request #33 from QURIresearch/lang-function-interface
Change the function interface into a js function.
This commit is contained in:
commit
4ebb11182f
2
packages/squiggle-lang/.gitignore
vendored
2
packages/squiggle-lang/.gitignore
vendored
|
@ -13,3 +13,5 @@ yarn-error.log
|
||||||
# Local Netlify folder
|
# Local Netlify folder
|
||||||
.netlify
|
.netlify
|
||||||
.idea
|
.idea
|
||||||
|
*.gen.ts
|
||||||
|
*.gen.js
|
||||||
|
|
|
@ -27,15 +27,20 @@ This package is mainly written in [ReScript](https://rescript-lang.org/). But ha
|
||||||
a typescript interface.
|
a typescript interface.
|
||||||
|
|
||||||
ReScript has an interesting philosophy of not providing much in the way of effective
|
ReScript has an interesting philosophy of not providing much in the way of effective
|
||||||
build tools. Every ReScript file is compiled into a .bs.js file with the same name
|
build tools. Every ReScript file is compiled into .bs.js and .gen.ts files with the same name
|
||||||
and same location, and then you can use these .bs.js files in other js files to
|
and same location, and then you can use these files in other js files to
|
||||||
create your program. To generate this .bs.js files to build the package, you run
|
create your program. To generate these files to build the package, you run
|
||||||
`yarn build`.
|
`yarn build`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn build
|
yarn build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
.gen.ts files are created by [genType](https://rescript-lang.org/docs/gentype/latest/getting-started),
|
||||||
|
which creates typescript typings for needed parts of the codebase so that they
|
||||||
|
can be easily used in typescript. These .gen.ts files reference the .bs.js files
|
||||||
|
generated by rescript.
|
||||||
|
|
||||||
You can also go `yarn start` for the purposes of watching for file changes and
|
You can also go `yarn start` for the purposes of watching for file changes and
|
||||||
rebuilding every time there is one.
|
rebuilding every time there is one.
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { run } from '../src/js/index';
|
||||||
|
|
||||||
describe("A simple result", () => {
|
describe("A simple result", () => {
|
||||||
test("mean(normal(5,2))", () => {
|
test("mean(normal(5,2))", () => {
|
||||||
expect(run("mean(normal(5,2))")).toEqual({ tag: 'Ok', value: {hd: { NAME: 'Float', VAL: 5 }, tl: 0} });
|
expect(run("mean(normal(5,2))")).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 5 } ] });
|
||||||
});
|
});
|
||||||
test("10+10", () => {
|
test("10+10", () => {
|
||||||
let foo = run("normal(5,2)");
|
let foo = run("normal(5,2)");
|
||||||
|
@ -10,6 +10,6 @@ describe("A simple result", () => {
|
||||||
});
|
});
|
||||||
test("log(1) = 0", () => {
|
test("log(1) = 0", () => {
|
||||||
let foo = run("log(1)");
|
let foo = run("log(1)");
|
||||||
expect(foo).toEqual({ tag: 'Ok', value: { hd: { NAME: 'Float', VAL: 0}, tl: 0}});
|
expect(foo).toEqual({ tag: 'Ok', value: [ { NAME: 'Float', VAL: 0} ]});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,7 +31,8 @@
|
||||||
"rationale"
|
"rationale"
|
||||||
],
|
],
|
||||||
"gentypeconfig": {
|
"gentypeconfig": {
|
||||||
"language": "untyped",
|
"language": "typescript",
|
||||||
|
"generatedFileExtension": ".gen.ts",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"shims": {},
|
"shims": {},
|
||||||
"debug": {
|
"debug": {
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
export {runAll as run} from '../rescript/ProgramEvaluator.gen'
|
import {runAll} from '../rescript/ProgramEvaluator.gen';
|
||||||
|
export type {t as DistPlus} from '../rescript/pointSetDist/DistPlus.gen';
|
||||||
|
export let run = runAll
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
/* Untyped file generated from ProgramEvaluator.res by genType. */
|
|
||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
const ProgramEvaluatorBS = require('./ProgramEvaluator.bs');
|
|
||||||
|
|
||||||
const runAll = function (Arg1) {
|
|
||||||
const result = ProgramEvaluatorBS.runAll(Arg1);
|
|
||||||
return result.TAG===0
|
|
||||||
? {tag:"Ok", value:result._0}
|
|
||||||
: {tag:"Error", value:result._0}
|
|
||||||
};;
|
|
||||||
exports.runAll = runAll
|
|
|
@ -5,7 +5,7 @@ module Inputs = {
|
||||||
sampleCount: option<int>,
|
sampleCount: option<int>,
|
||||||
outputXYPoints: option<int>,
|
outputXYPoints: option<int>,
|
||||||
kernelWidth: option<float>,
|
kernelWidth: option<float>,
|
||||||
pointSetDistLength: option<int>,
|
pointDistLength: option<int>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let defaultRecommendedLength = 100
|
let defaultRecommendedLength = 100
|
||||||
|
@ -21,7 +21,7 @@ module Inputs = {
|
||||||
sampleCount: None,
|
sampleCount: None,
|
||||||
outputXYPoints: None,
|
outputXYPoints: None,
|
||||||
kernelWidth: None,
|
kernelWidth: None,
|
||||||
pointSetDistLength: None,
|
pointDistLength: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
let make = (
|
let make = (
|
||||||
|
@ -36,13 +36,10 @@ module Inputs = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type exported = [
|
type exportType = [
|
||||||
| #DistPlus(DistPlus.t)
|
| #DistPlus(DistPlus.t)
|
||||||
| #Float(float)
|
| #Float(float)
|
||||||
| #Function(
|
| #Function((float) => Belt.Result.t<DistPlus.t,string>)
|
||||||
(array<string>, ASTTypes.node),
|
|
||||||
ASTTypes.environment,
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
module Internals = {
|
module Internals = {
|
||||||
|
@ -62,13 +59,13 @@ module Internals = {
|
||||||
graph: ASTTypes.node,
|
graph: ASTTypes.node,
|
||||||
pointSetDist: PointSetTypes.pointSetDist,
|
pointSetDist: PointSetTypes.pointSetDist,
|
||||||
}
|
}
|
||||||
let makeOutputs = (graph, pointSetDist): outputs => {graph: graph, pointSetDist: pointSetDist}
|
let makeOutputs = (graph, shape): outputs => {graph: graph, pointSetDist: shape}
|
||||||
|
|
||||||
let makeInputs = (inputs: Inputs.inputs): SamplingInputs.samplingInputs => {
|
let makeInputs = (inputs: Inputs.inputs): SamplingInputs.samplingInputs => {
|
||||||
sampleCount: inputs.samplingInputs.sampleCount |> E.O.default(10000),
|
sampleCount: inputs.samplingInputs.sampleCount |> E.O.default(10000),
|
||||||
outputXYPoints: inputs.samplingInputs.outputXYPoints |> E.O.default(10000),
|
outputXYPoints: inputs.samplingInputs.outputXYPoints |> E.O.default(10000),
|
||||||
kernelWidth: inputs.samplingInputs.kernelWidth,
|
kernelWidth: inputs.samplingInputs.kernelWidth,
|
||||||
pointSetDistLength: inputs.samplingInputs.pointSetDistLength |> E.O.default(10000),
|
pointSetDistLength: inputs.samplingInputs.pointDistLength |> E.O.default(10000),
|
||||||
}
|
}
|
||||||
|
|
||||||
let runNode = (inputs, node) =>
|
let runNode = (inputs, node) =>
|
||||||
|
@ -91,7 +88,7 @@ module Internals = {
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputsToLeaf = (inputs: Inputs.inputs) =>
|
let inputsToLeaf = (inputs: Inputs.inputs) =>
|
||||||
Parser.fromString(inputs.squiggleString) -> E.R.bind(g => runProgram(inputs, g))
|
Parser.fromString(inputs.squiggleString) |> E.R.bind(_, g => runProgram(inputs, g))
|
||||||
|
|
||||||
let outputToDistPlus = (inputs: Inputs.inputs, pointSetDist: PointSetTypes.pointSetDist) =>
|
let outputToDistPlus = (inputs: Inputs.inputs, pointSetDist: PointSetTypes.pointSetDist) =>
|
||||||
DistPlus.make(~pointSetDist, ~squiggleString=Some(inputs.squiggleString), ())
|
DistPlus.make(~pointSetDist, ~squiggleString=Some(inputs.squiggleString), ())
|
||||||
|
@ -121,12 +118,31 @@ let renderIfNeeded = (inputs: Inputs.inputs, node: ASTTypes.node): result<
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Consider using ASTTypes.getFloat or similar in this function
|
let rec returnDist = (functionInfo : (array<string>, ASTTypes.node),
|
||||||
let coersionToExportedTypes = (
|
inputs : Inputs.inputs,
|
||||||
|
env : ASTTypes.environment) => {
|
||||||
|
(input : float) => {
|
||||||
|
let foo: Inputs.inputs = {...inputs, environment: env};
|
||||||
|
evaluateFunction(
|
||||||
|
foo,
|
||||||
|
functionInfo,
|
||||||
|
[#SymbolicDist(#Float(input))],
|
||||||
|
) |> E.R.bind(_, a =>
|
||||||
|
switch a {
|
||||||
|
| #DistPlus(d) => Ok(DistPlus.T.normalize(d))
|
||||||
|
| n =>
|
||||||
|
Js.log2("Error here", n)
|
||||||
|
Error("wrong type")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Consider using ExpressionTypes.ExpressionTree.getFloat or similar in this function
|
||||||
|
and coersionToExportedTypes = (
|
||||||
inputs,
|
inputs,
|
||||||
env: ASTTypes.environment,
|
env: ASTTypes.environment,
|
||||||
node: ASTTypes.node,
|
node: ASTTypes.node,
|
||||||
): result<exported, string> =>
|
): result<exportType, string> =>
|
||||||
node
|
node
|
||||||
|> renderIfNeeded(inputs)
|
|> renderIfNeeded(inputs)
|
||||||
|> E.R.bind(_, x =>
|
|> E.R.bind(_, x =>
|
||||||
|
@ -134,31 +150,12 @@ let coersionToExportedTypes = (
|
||||||
| #RenderedDist(Discrete({xyShape: {xs: [x], ys: [1.0]}})) => Ok(#Float(x))
|
| #RenderedDist(Discrete({xyShape: {xs: [x], ys: [1.0]}})) => Ok(#Float(x))
|
||||||
| #SymbolicDist(#Float(x)) => Ok(#Float(x))
|
| #SymbolicDist(#Float(x)) => Ok(#Float(x))
|
||||||
| #RenderedDist(n) => Ok(#DistPlus(Internals.outputToDistPlus(inputs, n)))
|
| #RenderedDist(n) => Ok(#DistPlus(Internals.outputToDistPlus(inputs, n)))
|
||||||
| #Function(n) => Ok(#Function(n, env))
|
| #Function(n) => Ok(#Function(returnDist(n, inputs, env)))
|
||||||
| n => Error("Didn't output a rendered distribution. Format:" ++ AST.toString(n))
|
| n => Error("Didn't output a rendered distribution. Format:" ++ AST.toString(n))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
let rec mapM = (f, xs) =>
|
and evaluateFunction = (
|
||||||
switch xs {
|
|
||||||
| list{} => Ok(list{})
|
|
||||||
| list{x, ...rest} =>
|
|
||||||
switch f(x) {
|
|
||||||
| Error(err) => Error(err)
|
|
||||||
| Ok(val) =>
|
|
||||||
switch mapM(f, rest) {
|
|
||||||
| Error(err) => Error(err)
|
|
||||||
| Ok(restList) => Ok(list{val, ...restList})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let evaluateProgram = (inputs: Inputs.inputs) =>
|
|
||||||
inputs
|
|
||||||
|> Internals.inputsToLeaf
|
|
||||||
|> E.R.bind(_, xs => mapM(((a, b)) => coersionToExportedTypes(inputs, a, b), Array.to_list(xs)))
|
|
||||||
|
|
||||||
let evaluateFunction = (
|
|
||||||
inputs: Inputs.inputs,
|
inputs: Inputs.inputs,
|
||||||
fn: (array<string>, ASTTypes.node),
|
fn: (array<string>, ASTTypes.node),
|
||||||
fnInputs,
|
fnInputs,
|
||||||
|
@ -172,6 +169,29 @@ let evaluateFunction = (
|
||||||
output |> E.R.bind(_, coersionToExportedTypes(inputs, inputs.environment))
|
output |> E.R.bind(_, coersionToExportedTypes(inputs, inputs.environment))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let rec mapM = (f, xs) =>
|
||||||
|
switch xs {
|
||||||
|
| [] => Ok([])
|
||||||
|
| arr =>
|
||||||
|
switch f(arr[0]) {
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
| Ok(val) =>
|
||||||
|
switch mapM(f, Belt.Array.sliceToEnd(arr, 1)) {
|
||||||
|
| Error(err) => Error(err)
|
||||||
|
| Ok(restList) => Ok(Belt.Array.concat([val], restList))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let evaluateProgram = (inputs: Inputs.inputs) =>
|
||||||
|
inputs
|
||||||
|
|> Internals.inputsToLeaf
|
||||||
|
|> E.R.bind(_, xs => mapM(((a, b)) => coersionToExportedTypes(inputs, a, b), xs))
|
||||||
|
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let runAll = (squiggleString: string) => {
|
let runAll = (squiggleString: string) => {
|
||||||
let inputs = Inputs.make(
|
let inputs = Inputs.make(
|
||||||
|
@ -179,12 +199,12 @@ let runAll = (squiggleString: string) => {
|
||||||
sampleCount: Some(10000),
|
sampleCount: Some(10000),
|
||||||
outputXYPoints: Some(10000),
|
outputXYPoints: Some(10000),
|
||||||
kernelWidth: None,
|
kernelWidth: None,
|
||||||
pointSetDistLength: Some(1000),
|
pointDistLength: Some(1000),
|
||||||
},
|
},
|
||||||
~squiggleString,
|
~squiggleString,
|
||||||
~environment=[]->Belt.Map.String.fromArray,
|
~environment=[]->Belt.Map.String.fromArray,
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
let response1 = evaluateProgram(inputs);
|
let response1 = evaluateProgram(inputs);
|
||||||
response1;
|
response1
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
open PointSetTypes;
|
open PointSetTypes;
|
||||||
|
|
||||||
|
@genType
|
||||||
type t = PointSetTypes.distPlus;
|
type t = PointSetTypes.distPlus;
|
||||||
|
|
||||||
let pointSetDistIntegral = pointSetDist => PointSetDist.T.Integral.get(pointSetDist);
|
let pointSetDistIntegral = pointSetDist => PointSetDist.T.Integral.get(pointSetDist);
|
||||||
|
|
|
@ -55,6 +55,7 @@ type pointSetDistMonad<'a, 'b, 'c> =
|
||||||
| Discrete('b)
|
| Discrete('b)
|
||||||
| Continuous('c)
|
| Continuous('c)
|
||||||
|
|
||||||
|
@genType
|
||||||
type pointSetDist = pointSetDistMonad<mixedShape, discreteShape, continuousShape>
|
type pointSetDist = pointSetDistMonad<mixedShape, discreteShape, continuousShape>
|
||||||
|
|
||||||
module ShapeMonad = {
|
module ShapeMonad = {
|
||||||
|
@ -73,6 +74,7 @@ type generationSource =
|
||||||
type distributionUnit =
|
type distributionUnit =
|
||||||
| UnspecifiedDistribution
|
| UnspecifiedDistribution
|
||||||
|
|
||||||
|
@genType
|
||||||
type distPlus = {
|
type distPlus = {
|
||||||
pointSetDist: pointSetDist,
|
pointSetDist: pointSetDist,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user