Change function to simpler interface

This commit is contained in:
Sam Nolan 2022-02-27 15:25:30 +11:00
parent a7529d89f8
commit 44da21370c
10 changed files with 5281 additions and 273 deletions

View File

@ -13,3 +13,5 @@ yarn-error.log
# Local Netlify folder # Local Netlify folder
.netlify .netlify
.idea .idea
*.gen.ts
*.gen.js

View File

@ -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.

View File

@ -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} ]});
}) })
}); });

View File

@ -31,7 +31,8 @@
"rationale" "rationale"
], ],
"gentypeconfig": { "gentypeconfig": {
"language": "untyped", "language": "typescript",
"generatedFileExtension": ".gen.ts",
"module": "commonjs", "module": "commonjs",
"shims": {}, "shims": {},
"debug": { "debug": {

View File

@ -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

View File

@ -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

View File

@ -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
} }

View File

@ -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);

View File

@ -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,

5423
yarn.lock

File diff suppressed because it is too large Load Diff