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