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
|
||||
.netlify
|
||||
.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.
|
||||
|
||||
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
|
||||
and same location, and then you can use these .bs.js files in other js files to
|
||||
create your program. To generate this .bs.js files to build the package, you run
|
||||
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 files in other js files to
|
||||
create your program. To generate these files to build the package, you run
|
||||
`yarn build`.
|
||||
|
||||
```bash
|
||||
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
|
||||
rebuilding every time there is one.
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { run } from '../src/js/index';
|
|||
|
||||
describe("A simple result", () => {
|
||||
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", () => {
|
||||
let foo = run("normal(5,2)");
|
||||
|
@ -10,6 +10,6 @@ describe("A simple result", () => {
|
|||
});
|
||||
test("log(1) = 0", () => {
|
||||
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"
|
||||
],
|
||||
"gentypeconfig": {
|
||||
"language": "untyped",
|
||||
"language": "typescript",
|
||||
"generatedFileExtension": ".gen.ts",
|
||||
"module": "commonjs",
|
||||
"shims": {},
|
||||
"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>,
|
||||
outputXYPoints: option<int>,
|
||||
kernelWidth: option<float>,
|
||||
pointSetDistLength: option<int>,
|
||||
pointDistLength: option<int>,
|
||||
}
|
||||
}
|
||||
let defaultRecommendedLength = 100
|
||||
|
@ -21,7 +21,7 @@ module Inputs = {
|
|||
sampleCount: None,
|
||||
outputXYPoints: None,
|
||||
kernelWidth: None,
|
||||
pointSetDistLength: None,
|
||||
pointDistLength: None,
|
||||
}
|
||||
|
||||
let make = (
|
||||
|
@ -36,13 +36,10 @@ module Inputs = {
|
|||
}
|
||||
}
|
||||
|
||||
type exported = [
|
||||
type exportType = [
|
||||
| #DistPlus(DistPlus.t)
|
||||
| #Float(float)
|
||||
| #Function(
|
||||
(array<string>, ASTTypes.node),
|
||||
ASTTypes.environment,
|
||||
)
|
||||
| #Function((float) => Belt.Result.t<DistPlus.t,string>)
|
||||
]
|
||||
|
||||
module Internals = {
|
||||
|
@ -62,13 +59,13 @@ module Internals = {
|
|||
graph: ASTTypes.node,
|
||||
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 => {
|
||||
sampleCount: inputs.samplingInputs.sampleCount |> E.O.default(10000),
|
||||
outputXYPoints: inputs.samplingInputs.outputXYPoints |> E.O.default(10000),
|
||||
kernelWidth: inputs.samplingInputs.kernelWidth,
|
||||
pointSetDistLength: inputs.samplingInputs.pointSetDistLength |> E.O.default(10000),
|
||||
pointSetDistLength: inputs.samplingInputs.pointDistLength |> E.O.default(10000),
|
||||
}
|
||||
|
||||
let runNode = (inputs, node) =>
|
||||
|
@ -91,7 +88,7 @@ module Internals = {
|
|||
}
|
||||
|
||||
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) =>
|
||||
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 coersionToExportedTypes = (
|
||||
let rec returnDist = (functionInfo : (array<string>, ASTTypes.node),
|
||||
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,
|
||||
env: ASTTypes.environment,
|
||||
node: ASTTypes.node,
|
||||
): result<exported, string> =>
|
||||
): result<exportType, string> =>
|
||||
node
|
||||
|> renderIfNeeded(inputs)
|
||||
|> E.R.bind(_, x =>
|
||||
|
@ -134,31 +150,12 @@ let coersionToExportedTypes = (
|
|||
| #RenderedDist(Discrete({xyShape: {xs: [x], ys: [1.0]}})) => Ok(#Float(x))
|
||||
| #SymbolicDist(#Float(x)) => Ok(#Float(x))
|
||||
| #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))
|
||||
}
|
||||
)
|
||||
|
||||
let rec mapM = (f, xs) =>
|
||||
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 = (
|
||||
and evaluateFunction = (
|
||||
inputs: Inputs.inputs,
|
||||
fn: (array<string>, ASTTypes.node),
|
||||
fnInputs,
|
||||
|
@ -172,6 +169,29 @@ let evaluateFunction = (
|
|||
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
|
||||
let runAll = (squiggleString: string) => {
|
||||
let inputs = Inputs.make(
|
||||
|
@ -179,12 +199,12 @@ let runAll = (squiggleString: string) => {
|
|||
sampleCount: Some(10000),
|
||||
outputXYPoints: Some(10000),
|
||||
kernelWidth: None,
|
||||
pointSetDistLength: Some(1000),
|
||||
pointDistLength: Some(1000),
|
||||
},
|
||||
~squiggleString,
|
||||
~environment=[]->Belt.Map.String.fromArray,
|
||||
(),
|
||||
)
|
||||
let response1 = evaluateProgram(inputs);
|
||||
response1;
|
||||
response1
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
open PointSetTypes;
|
||||
|
||||
@genType
|
||||
type t = PointSetTypes.distPlus;
|
||||
|
||||
let pointSetDistIntegral = pointSetDist => PointSetDist.T.Integral.get(pointSetDist);
|
||||
|
|
|
@ -55,6 +55,7 @@ type pointSetDistMonad<'a, 'b, 'c> =
|
|||
| Discrete('b)
|
||||
| Continuous('c)
|
||||
|
||||
@genType
|
||||
type pointSetDist = pointSetDistMonad<mixedShape, discreteShape, continuousShape>
|
||||
|
||||
module ShapeMonad = {
|
||||
|
@ -73,6 +74,7 @@ type generationSource =
|
|||
type distributionUnit =
|
||||
| UnspecifiedDistribution
|
||||
|
||||
@genType
|
||||
type distPlus = {
|
||||
pointSetDist: pointSetDist,
|
||||
domain: domain,
|
||||
|
|
Loading…
Reference in New Issue
Block a user