From 74da6a0ae2e5646ee964b79c73eab03ac0e23a0f Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 19:09:29 +0200 Subject: [PATCH 01/33] shorter tests --- .../Reducer_MathJsParse_test.res | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 4acfc1c1..4e67f3d6 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -7,32 +7,38 @@ open Expect let expectParseToBe = (expr, answer) => Parse.parse(expr)->Result.flatMap(Parse.castNodeType)->Parse.toStringResult->expect->toBe(answer) +let testParse = (expr, answer) => + test(expr, () => expectParseToBe(expr, answer)) + +let skipTestParse = (expr, answer) => + Skip.test(expr, () => expectParseToBe(expr, answer)) + describe("MathJs parse", () => { describe("literals operators paranthesis", () => { - test("1", () => expectParseToBe("1", "1")) - test("'hello'", () => expectParseToBe("'hello'", "'hello'")) - test("true", () => expectParseToBe("true", "true")) - test("1+2", () => expectParseToBe("1+2", "add(1, 2)")) - test("add(1,2)", () => expectParseToBe("add(1,2)", "add(1, 2)")) - test("(1)", () => expectParseToBe("(1)", "(1)")) - test("(1+2)", () => expectParseToBe("(1+2)", "(add(1, 2))")) + testParse("1", "1") + testParse("'hello'", "'hello'") + testParse("true", "true") + testParse("1+2", "add(1, 2)") + testParse("add(1,2)", "add(1, 2)") + testParse("(1)", "(1)") + testParse("(1+2)", "(add(1, 2))") }) describe("variables", () => { - Skip.test("define", () => expectParseToBe("x = 1", "???")) - Skip.test("use", () => expectParseToBe("x", "???")) + skipTestParse("x = 1", "???") + skipTestParse("x", "???") }) describe("functions", () => { - Skip.test("define", () => expectParseToBe("identity(x) = x", "???")) - Skip.test("use", () => expectParseToBe("identity(x)", "???")) + skipTestParse("identity(x) = x", "???") + skipTestParse("identity(x)", "???") }) describe("arrays", () => { test("empty", () => expectParseToBe("[]", "[]")) test("define", () => expectParseToBe("[0, 1, 2]", "[0, 1, 2]")) test("define with strings", () => expectParseToBe("['hello', 'world']", "['hello', 'world']")) - Skip.test("range", () => expectParseToBe("range(0, 4)", "range(0, 4)")) + skipTestParse("range(0, 4)", "range(0, 4)") test("index", () => expectParseToBe("([0,1,2])[1]", "([0, 1, 2])[1]")) }) From bbcd7f26409b73ea8206ef90897cb7e6bddc2470 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 19:18:10 +0200 Subject: [PATCH 02/33] shorter tests --- .../__tests__/Reducer/Reducer_test.res | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 288cbabe..436c4f7c 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -1,6 +1,12 @@ open Jest open Reducer_TestHelpers +let testParseToBe = (expr, answer) => + test(expr, () => expectParseToBe(expr, answer)) + +let testEvalToBe = (expr, answer) => + test(expr, () => expectEvalToBe(expr, answer)) + describe("reducer using mathjs parse", () => { // Test the MathJs parser compatibility // Those tests toString that there is a semantic mapping from MathJs to Expression @@ -10,20 +16,20 @@ describe("reducer using mathjs parse", () => { // Those tests toString that we are converting mathjs parse tree to what we need describe("expressions", () => { - test("1", () => expectParseToBe("1", "Ok(1)")) - test("(1)", () => expectParseToBe("(1)", "Ok(1)")) - test("1+2", () => expectParseToBe("1+2", "Ok((:add 1 2))")) - test("(1+2)", () => expectParseToBe("1+2", "Ok((:add 1 2))")) - test("add(1,2)", () => expectParseToBe("1+2", "Ok((:add 1 2))")) - test("1+2*3", () => expectParseToBe("1+2*3", "Ok((:add 1 (:multiply 2 3)))")) + testParseToBe("1", "Ok(1)") + testParseToBe("(1)", "Ok(1)") + testParseToBe("1+2", "Ok((:add 1 2))") + testParseToBe("1+2", "Ok((:add 1 2))") + testParseToBe("1+2", "Ok((:add 1 2))") + testParseToBe("1+2*3", "Ok((:add 1 (:multiply 2 3)))") }) describe("arrays", () => { //Note. () is a empty list in Lisp // The only builtin structure in Lisp is list. There are no arrays // [1,2,3] becomes (1 2 3) test("empty", () => expectParseToBe("[]", "Ok(())")) - test("[1, 2, 3]", () => expectParseToBe("[1, 2, 3]", "Ok((1 2 3))")) - test("['hello', 'world']", () => expectParseToBe("['hello', 'world']", "Ok(('hello' 'world'))")) + testParseToBe("[1, 2, 3]", "Ok((1 2 3))") + testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))") test("index", () => expectParseToBe("([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))")) }) describe("records", () => { @@ -45,20 +51,20 @@ describe("eval", () => { // See https://mathjs.org/docs/expressions/syntax.html // See https://mathjs.org/docs/reference/functions.html describe("expressions", () => { - test("1", () => expectEvalToBe("1", "Ok(1)")) - test("1+2", () => expectEvalToBe("1+2", "Ok(3)")) - test("(1+2)*3", () => expectEvalToBe("(1+2)*3", "Ok(9)")) - test("2>1", () => expectEvalToBe("2>1", "Ok(true)")) - test("concat('a ', 'b')", () => expectEvalToBe("concat('a ', 'b')", "Ok('a b')")) - test("log(10)", () => expectEvalToBe("log(10)", "Ok(2.302585092994046)")) - test("cos(10)", () => expectEvalToBe("cos(10)", "Ok(-0.8390715290764524)")) + testEvalToBe("1", "Ok(1)") + testEvalToBe("1+2", "Ok(3)") + testEvalToBe("(1+2)*3", "Ok(9)") + testEvalToBe("2>1", "Ok(true)") + testEvalToBe("concat('a ', 'b')", "Ok('a b')") + testEvalToBe("log(10)", "Ok(2.302585092994046)") + testEvalToBe("cos(10)", "Ok(-0.8390715290764524)") // TODO more built ins }) describe("arrays", () => { test("empty array", () => expectEvalToBe("[]", "Ok([])")) - test("[1, 2, 3]", () => expectEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])")) - test("['hello', 'world']", () => expectEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])")) - test("index", () => expectEvalToBe("([0,1,2])[1]", "Ok(1)")) + testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])") + testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])") + testEvalToBe("([0,1,2])[1]", "Ok(1)") test("index not found", () => expectEvalToBe("([0,1,2])[10]", "Error(Array index not found: 10)") ) From 4e6a2341f08bc86de9a57b3b51b9cf36fe5d759a Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 19:36:19 +0200 Subject: [PATCH 03/33] shorter tests --- .../Reducer_MathJsParse_test.res | 14 +++++-- .../__tests__/Reducer/Reducer_test.res | 39 +++++++++---------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 4e67f3d6..41ba6239 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -10,9 +10,15 @@ let expectParseToBe = (expr, answer) => let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) +let testDescParse = (desc, expr, answer) => + test(desc, () => expectParseToBe(expr, answer)) + let skipTestParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) +let skipDescTestParse = (desc, expr, answer) => + Skip.test(desc, () => expectParseToBe(expr, answer)) + describe("MathJs parse", () => { describe("literals operators paranthesis", () => { testParse("1", "1") @@ -43,15 +49,15 @@ describe("MathJs parse", () => { }) describe("records", () => { - test("define", () => expectParseToBe("{a: 1, b: 2}", "{a: 1, b: 2}")) - test("use", () => expectParseToBe("record.property", "record['property']")) + testDescParse("define", "{a: 1, b: 2}", "{a: 1, b: 2}") + testDescParse("use", "record.property", "record['property']") }) describe("comments", () => { - Skip.test("define", () => expectParseToBe("# This is a comment", "???")) + skipDescTestParse("define", "# This is a comment", "???") }) describe("if statement", () => { - Skip.test("define", () => expectParseToBe("if (true) { 1 } else { 0 }", "???")) + skipDescTestParse("define", "if (true) { 1 } else { 0 }", "???") }) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 436c4f7c..7f6ae6f1 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -1,12 +1,19 @@ open Jest open Reducer_TestHelpers + let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) +let testDescParseToBe = (desc, expr, answer) => + test(desc, () => expectParseToBe(expr, answer)) + let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) +let testDescEvalToBe = (desc, expr, answer) => + test(desc, () => expectEvalToBe(expr, answer)) + describe("reducer using mathjs parse", () => { // Test the MathJs parser compatibility // Those tests toString that there is a semantic mapping from MathJs to Expression @@ -27,21 +34,17 @@ describe("reducer using mathjs parse", () => { //Note. () is a empty list in Lisp // The only builtin structure in Lisp is list. There are no arrays // [1,2,3] becomes (1 2 3) - test("empty", () => expectParseToBe("[]", "Ok(())")) + testDescParseToBe("empty", "[]", "Ok(())") testParseToBe("[1, 2, 3]", "Ok((1 2 3))") testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))") - test("index", () => expectParseToBe("([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))")) + testDescParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))") }) describe("records", () => { - test("define", () => - expectParseToBe("{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") - ) - test("use", () => - expectParseToBe( + testDescParseToBe("define", + "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") + testDescParseToBe("use", "{a: 1, b: 2}.a", - "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))", - ) - ) + "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))") }) }) @@ -65,9 +68,8 @@ describe("eval", () => { testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])") testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])") testEvalToBe("([0,1,2])[1]", "Ok(1)") - test("index not found", () => - expectEvalToBe("([0,1,2])[10]", "Error(Array index not found: 10)") - ) + testDescEvalToBe("index not found", + "([0,1,2])[10]", "Error(Array index not found: 10)") }) describe("records", () => { test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1, b: 2})")) @@ -77,11 +79,8 @@ describe("eval", () => { }) describe("test exceptions", () => { - test("javascript exception", () => - expectEvalToBe("jsraise('div by 0')", "Error(JS Exception: Error: 'div by 0')") - ) - - test("rescript exception", () => - expectEvalToBe("resraise()", "Error(TODO: unhandled rescript exception)") - ) + testDescEvalToBe("javascript exception", + "jsraise('div by 0')", "Error(JS Exception: Error: 'div by 0')") + testDescEvalToBe("rescript exception", + "resraise()", "Error(TODO: unhandled rescript exception)") }) From 05e8540b316336b23d87afc5c31fe85f22e4b8e3 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 20:51:54 +0200 Subject: [PATCH 04/33] rescript:format --- packages/squiggle-lang/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index 02de65be..f7fd85f3 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -10,7 +10,8 @@ "test:reducer": "jest --testPathPattern '.*__tests__/Reducer.*'", "test": "jest", "test:watch": "jest --watchAll", - "all": "yarn build && yarn bundle && yarn test" + "all": "yarn build && yarn bundle && yarn test", + "rescript:format": "find . -type f \\( -name '*.res' -o -name '*.resi' \\) -exec sh -c 'bsc -format {} | sponge {}' \\;" }, "keywords": [ "Rescript" From a5bb390370a8e730418c3dbc92c87f27311669e1 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 20:54:51 +0200 Subject: [PATCH 05/33] reformat --- .../__tests__/Reducer/Reducer_test.res | 37 +++++++++---------- .../Reducer_Expression.resi | 20 ++-------- .../Reducer_MathJs_ToExpression.res | 5 ++- .../ReducerInterface_ExpressionValue.res | 5 ++- 4 files changed, 29 insertions(+), 38 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 7f6ae6f1..a7539b7f 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -1,18 +1,13 @@ open Jest open Reducer_TestHelpers +let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testParseToBe = (expr, answer) => - test(expr, () => expectParseToBe(expr, answer)) +let testDescParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) -let testDescParseToBe = (desc, expr, answer) => - test(desc, () => expectParseToBe(expr, answer)) +let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) -let testEvalToBe = (expr, answer) => - test(expr, () => expectEvalToBe(expr, answer)) - -let testDescEvalToBe = (desc, expr, answer) => - test(desc, () => expectEvalToBe(expr, answer)) +let testDescEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer)) describe("reducer using mathjs parse", () => { // Test the MathJs parser compatibility @@ -40,11 +35,12 @@ describe("reducer using mathjs parse", () => { testDescParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))") }) describe("records", () => { - testDescParseToBe("define", - "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") - testDescParseToBe("use", - "{a: 1, b: 2}.a", - "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))") + testDescParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") + testDescParseToBe( + "use", + "{a: 1, b: 2}.a", + "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))", + ) }) }) @@ -68,8 +64,7 @@ describe("eval", () => { testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])") testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])") testEvalToBe("([0,1,2])[1]", "Ok(1)") - testDescEvalToBe("index not found", - "([0,1,2])[10]", "Error(Array index not found: 10)") + testDescEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)") }) describe("records", () => { test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1, b: 2})")) @@ -79,8 +74,10 @@ describe("eval", () => { }) describe("test exceptions", () => { - testDescEvalToBe("javascript exception", - "jsraise('div by 0')", "Error(JS Exception: Error: 'div by 0')") - testDescEvalToBe("rescript exception", - "resraise()", "Error(TODO: unhandled rescript exception)") + testDescEvalToBe( + "javascript exception", + "jsraise('div by 0')", + "Error(JS Exception: Error: 'div by 0')", + ) + testDescEvalToBe("rescript exception", "resraise()", "Error(TODO: unhandled rescript exception)") }) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi index 8b09c516..afd0105f 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi @@ -9,20 +9,8 @@ let parse: string => result module MapString = Belt.Map.String type bindings = MapString.t let defaultBindings: bindings -let reduceValueList: list => result< - expressionValue, - Reducer_ErrorValue.t, -> -let reduceExpression: (expression, 'a) => result< - expressionValue, - Reducer_ErrorValue.t, -> -let evalWBindingsExpression: (expression, 'a) => result< - expressionValue, - Reducer_ErrorValue.t, -> -let evalWBindings: (string, bindings) => Result.t< - expressionValue, - Reducer_ErrorValue.t, -> +let reduceValueList: list => result +let reduceExpression: (expression, 'a) => result +let evalWBindingsExpression: (expression, 'a) => result +let evalWBindings: (string, bindings) => Result.t let eval: string => Result.t diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res index 5b16fb54..edd0313b 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res @@ -54,7 +54,10 @@ let rec fromNode = (mathJsNode: Parse.node): result => Ok(list{}), (racc, currentPropertyMathJsNode) => racc->Result.flatMap(acc => - fromNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{propertyCode, ...acc}) + fromNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{ + propertyCode, + ...acc, + }) ), ) rpropertyCodeList->Result.map(propertyCodeList => ExtressionT.EList(propertyCodeList)) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 8c94d752..1aeca2f1 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -23,7 +23,10 @@ let rec toString = aValue => | EvSymbol(aString) => `:${aString}` | EvArray(anArray) => { let args = - anArray->Belt.Array.map(each => toString(each))->Extra_Array.interperse(", ")->Js.String.concatMany("") + anArray + ->Belt.Array.map(each => toString(each)) + ->Extra_Array.interperse(", ") + ->Js.String.concatMany("") `[${args}]` } | EvRecord(aRecord) => { From 84f3420369d990fdc4fbda73975cf44ceca79d3a Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 22:02:06 +0200 Subject: [PATCH 06/33] parse assignment --- .../Reducer_MathJsParse_test.res | 14 +++----- .../rescript/Reducer/Reducer_ErrorValue.res | 2 ++ .../Reducer_MathJs/Reducer_MathJs_Parse.res | 33 ++++++++++++++++--- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 41ba6239..31cbeb63 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -7,17 +7,13 @@ open Expect let expectParseToBe = (expr, answer) => Parse.parse(expr)->Result.flatMap(Parse.castNodeType)->Parse.toStringResult->expect->toBe(answer) -let testParse = (expr, answer) => - test(expr, () => expectParseToBe(expr, answer)) +let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testDescParse = (desc, expr, answer) => - test(desc, () => expectParseToBe(expr, answer)) +let testDescParse = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) -let skipTestParse = (expr, answer) => - Skip.test(expr, () => expectParseToBe(expr, answer)) +let skipTestParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) -let skipDescTestParse = (desc, expr, answer) => - Skip.test(desc, () => expectParseToBe(expr, answer)) +let skipDescTestParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) describe("MathJs parse", () => { describe("literals operators paranthesis", () => { @@ -31,7 +27,7 @@ describe("MathJs parse", () => { }) describe("variables", () => { - skipTestParse("x = 1", "???") + testParse("x = 1", "x = 1") skipTestParse("x", "???") }) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index 4f57bc2c..70601726 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -3,6 +3,7 @@ type errorValue = | REFunctionExpected(string) | REJavaScriptExn(option, option) // Javascript Exception | RERecordPropertyNotFound(string, string) + | RESyntaxError(string) | RETodo(string) // To do type t = errorValue @@ -24,5 +25,6 @@ let errorToString = err => answer } | RERecordPropertyNotFound(msg, index) => `${msg}: ${index}` + | RESyntaxError(desc) => `Syntax Error: ${desc}` | RETodo(msg) => `TODO: ${msg}` } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res index bfd186e0..15ef6e26 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res @@ -7,7 +7,6 @@ open Reducer_ErrorValue type node = {"type": string, "isNode": bool, "comment": string} type arrayNode = {...node, "items": array} -//assignmentNode //blockNode //conditionalNode type constantNode = {...node, "value": unit} @@ -23,9 +22,15 @@ type parenthesisNode = {...node, "content": node} //rangeNode //relationalNode type symbolNode = {...node, "name": string} +type assignmentNode = {...node, "object": symbolNode, "value": node} +type assignmentNodeWAccessor = {...node, "object": accessorNode, "value": node} +type assignmentNodeWIndex = {...assignmentNodeWAccessor, "index": Js.null} external castAccessorNode: node => accessorNode = "%identity" external castArrayNode: node => arrayNode = "%identity" +external castAssignmentNode: node => assignmentNode = "%identity" +external castAssignmentNodeWAccessor: node => assignmentNodeWAccessor = "%identity" +external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity" external castConstantNode: node => constantNode = "%identity" external castFunctionNode: node => functionNode = "%identity" external castIndexNode: node => indexNode = "%identity" @@ -50,6 +55,7 @@ let parse = (expr: string): result => type mathJsNode = | MjAccessorNode(accessorNode) | MjArrayNode(arrayNode) + | MjAssignmentNode(assignmentNode) | MjConstantNode(constantNode) | MjFunctionNode(functionNode) | MjIndexNode(indexNode) @@ -58,10 +64,20 @@ type mathJsNode = | MjParenthesisNode(parenthesisNode) | MjSymbolNode(symbolNode) -let castNodeType = (node: node) => +let castNodeType = (node: node) => { + let decideAssignmentNode = node => { + let iNode = node->castAssignmentNodeWIndex + if Js.Null.test(iNode["index"]) && iNode["object"]["type"] == "SymbolNode" { + node->castAssignmentNode->MjAssignmentNode->Ok + } else { + RESyntaxError("Assignment to index or property not supported")->Error + } + } + switch node["type"] { | "AccessorNode" => node->castAccessorNode->MjAccessorNode->Ok | "ArrayNode" => node->castArrayNode->MjArrayNode->Ok + | "AssignmentNode" => node->decideAssignmentNode | "ConstantNode" => node->castConstantNode->MjConstantNode->Ok | "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok | "IndexNode" => node->castIndexNode->MjIndexNode->Ok @@ -71,6 +87,7 @@ let castNodeType = (node: node) => | "SymbolNode" => node->castSymbolNode->MjSymbolNode->Ok | _ => RETodo(`Argg, unhandled MathJsNode: ${node["type"]}`)->Error } +} let rec toString = (mathJsNode: mathJsNode): string => { let toStringValue = (a: 'a): string => @@ -89,7 +106,8 @@ let rec toString = (mathJsNode: mathJsNode): string => { let toStringFunctionNode = (fnode: functionNode): string => `${fnode["fn"]}(${fnode["args"]->toStringNodeArray})` - let toStringObjectEntry = ((key: string, value: node)): string => `${key}: ${value->toStringMathJsNode}` + let toStringObjectEntry = ((key: string, value: node)): string => + `${key}: ${value->toStringMathJsNode}` let toStringObjectNode = (oNode: objectNode): string => `{${oNode["properties"] @@ -103,16 +121,21 @@ let rec toString = (mathJsNode: mathJsNode): string => { ->Belt.Array.map(each => toStringResult(each->castNodeType)) ->Js.String.concatMany("") + let toStringSymbolNode = (sNode: symbolNode): string => sNode["name"] + switch mathJsNode { - | MjAccessorNode(aNode) => `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]` + | MjAccessorNode(aNode) => + `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]` | MjArrayNode(aNode) => `[${aNode["items"]->toStringNodeArray}]` + | MjAssignmentNode(aNode) => + `${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}` | MjConstantNode(cNode) => cNode["value"]->toStringValue | MjFunctionNode(fNode) => fNode->toStringFunctionNode | MjIndexNode(iNode) => iNode->toStringIndexNode | MjObjectNode(oNode) => oNode->toStringObjectNode | MjOperatorNode(opNode) => opNode->castOperatorNodeToFunctionNode->toStringFunctionNode | MjParenthesisNode(pNode) => `(${toStringMathJsNode(pNode["content"])})` - | MjSymbolNode(sNode) => sNode["name"] + | MjSymbolNode(sNode) => sNode->toStringSymbolNode } } and toStringResult = (rMathJsNode: result): string => From cd7a4b748ee73f87db406080606a2bc33230bce2 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 22:03:03 +0200 Subject: [PATCH 07/33] assignment test --- .../Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 31cbeb63..ea302776 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -29,6 +29,7 @@ describe("MathJs parse", () => { describe("variables", () => { testParse("x = 1", "x = 1") skipTestParse("x", "???") + skipTestParse("x = 1; x", "???") }) describe("functions", () => { From 63a765a4fe515f48d3e3efbbce3508d318c4ffb9 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 5 Apr 2022 23:03:32 +0200 Subject: [PATCH 08/33] mathjs parse assignment --- .../Reducer_MathJs/Reducer_MathJsParse_test.res | 4 ++-- .../Reducer_MathJs/Reducer_MathJs_Parse.res | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index ea302776..4ec86785 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -28,8 +28,8 @@ describe("MathJs parse", () => { describe("variables", () => { testParse("x = 1", "x = 1") - skipTestParse("x", "???") - skipTestParse("x = 1; x", "???") + testParse("x", "x") + testParse("x = 1; x", "{x = 1; x}") }) describe("functions", () => { diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res index 15ef6e26..7f20bacf 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res @@ -7,7 +7,8 @@ open Reducer_ErrorValue type node = {"type": string, "isNode": bool, "comment": string} type arrayNode = {...node, "items": array} -//blockNode +type block = {"node": node} +type blockNode = {...node, "blocks": array} //conditionalNode type constantNode = {...node, "value": unit} //functionAssignmentNode @@ -31,6 +32,7 @@ external castArrayNode: node => arrayNode = "%identity" external castAssignmentNode: node => assignmentNode = "%identity" external castAssignmentNodeWAccessor: node => assignmentNodeWAccessor = "%identity" external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity" +external castBlockNode: node => blockNode = "%identity" external castConstantNode: node => constantNode = "%identity" external castFunctionNode: node => functionNode = "%identity" external castIndexNode: node => indexNode = "%identity" @@ -56,6 +58,7 @@ type mathJsNode = | MjAccessorNode(accessorNode) | MjArrayNode(arrayNode) | MjAssignmentNode(assignmentNode) + | MjBlockNode(blockNode) | MjConstantNode(constantNode) | MjFunctionNode(functionNode) | MjIndexNode(indexNode) @@ -67,7 +70,7 @@ type mathJsNode = let castNodeType = (node: node) => { let decideAssignmentNode = node => { let iNode = node->castAssignmentNodeWIndex - if Js.Null.test(iNode["index"]) && iNode["object"]["type"] == "SymbolNode" { + if Js.null == iNode["index"] && iNode["object"]["type"] == "SymbolNode" { node->castAssignmentNode->MjAssignmentNode->Ok } else { RESyntaxError("Assignment to index or property not supported")->Error @@ -78,6 +81,7 @@ let castNodeType = (node: node) => { | "AccessorNode" => node->castAccessorNode->MjAccessorNode->Ok | "ArrayNode" => node->castArrayNode->MjArrayNode->Ok | "AssignmentNode" => node->decideAssignmentNode + | "BlockNode" => node->castBlockNode->MjBlockNode->Ok | "ConstantNode" => node->castConstantNode->MjConstantNode->Ok | "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok | "IndexNode" => node->castIndexNode->MjIndexNode->Ok @@ -123,12 +127,19 @@ let rec toString = (mathJsNode: mathJsNode): string => { let toStringSymbolNode = (sNode: symbolNode): string => sNode["name"] + let toStringBlocks = (blocks: array): string => + blocks + ->Belt.Array.map(each => each["node"]->castNodeType->toStringResult) + ->Extra.Array.interperse("; ") + ->Js.String.concatMany("") + switch mathJsNode { | MjAccessorNode(aNode) => `${aNode["object"]->toStringMathJsNode}[${aNode["index"]->toStringIndexNode}]` | MjArrayNode(aNode) => `[${aNode["items"]->toStringNodeArray}]` | MjAssignmentNode(aNode) => `${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}` + | MjBlockNode(bNode) => `{${bNode["blocks"]->toStringBlocks}}` | MjConstantNode(cNode) => cNode["value"]->toStringValue | MjFunctionNode(fNode) => fNode->toStringFunctionNode | MjIndexNode(iNode) => iNode->toStringIndexNode From 660c0c70aec2ca56ad6e4f26471f481ec25a967e Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Fri, 8 Apr 2022 14:14:37 +0200 Subject: [PATCH 09/33] variables and statements format only reducer reformat lint multi-line test spelling multi-line semantic mapping todo multi-line eval multi-line tests todo change context to bindings simplify tests rename exception test methods bindings is an expression value make bindings callable reformat Emphasize the nature of Lisp AST Initial definition of macros make functions private fixed functionNode type casting macro call skeleton sort ReducerInterface fix test macros skeleton bindings is not a value assignment semantics let semantics defined format reformat reformat TODO function calls and list hd variables are confused reformat tmp works reformat reformat add test reformat add test --- .../Reducer_Dispatch_BuiltIn_test.res | 11 +- .../Reducer_MathJsParse_test.res | 30 ++-- .../__tests__/Reducer/Reducer_test.res | 26 ++- packages/squiggle-lang/package.json | 1 + .../Reducer_Dispatch_BuiltIn.res | 4 +- .../rescript/Reducer/Reducer_ErrorValue.res | 8 + .../Reducer_Expression/Reducer_Expression.res | 152 ++++++++++++++---- .../Reducer_Expression.resi | 16 -- .../Reducer_Expression_T.res | 10 ++ .../Reducer_MathJs/Reducer_MathJs_Parse.res | 21 ++- .../Reducer_MathJs_ToExpression.res | 101 +++++++++--- .../ReducerInterface_ExpressionValue.res | 11 +- 12 files changed, 288 insertions(+), 103 deletions(-) delete mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res index 2fd2a976..d8a6748c 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res @@ -6,15 +6,18 @@ open Expect let expectEvalToBe = (expr: string, answer: string) => Reducer.eval(expr)->ExpressionValue.toStringResult->expect->toBe(answer) +let testEval = (expr, answer) => + test(expr, () => expectEvalToBe(expr, answer)) + describe("builtin", () => { // All MathJs operators and functions are available for string, number and boolean // .e.g + - / * > >= < <= == /= not and or // See https://mathjs.org/docs/expressions/syntax.html // See https://mathjs.org/docs/reference/functions.html - test("-1", () => expectEvalToBe("-1", "Ok(-1)")) - test("1-1", () => expectEvalToBe("1-1", "Ok(0)")) - test("2>1", () => expectEvalToBe("2>1", "Ok(true)")) - test("concat('a','b')", () => expectEvalToBe("concat('a','b')", "Ok('ab')")) + testEval("-1", "Ok(-1)") + testEval("1-1", "Ok(0)") + testEval("2>1", "Ok(true)") + testEval("concat('a','b')", "Ok('ab')") }) describe("builtin exception", () => { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 4ec86785..fce588f1 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -11,9 +11,11 @@ let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer) let testDescParse = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) -let skipTestParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) +module MySkip = { + let testParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) -let skipDescTestParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) + let testDescParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) +} describe("MathJs parse", () => { describe("literals operators paranthesis", () => { @@ -26,6 +28,10 @@ describe("MathJs parse", () => { testParse("(1+2)", "(add(1, 2))") }) + describe("multi-line", () => { + testParse("1; 2", "{1; 2}") + }) + describe("variables", () => { testParse("x = 1", "x = 1") testParse("x", "x") @@ -33,16 +39,16 @@ describe("MathJs parse", () => { }) describe("functions", () => { - skipTestParse("identity(x) = x", "???") - skipTestParse("identity(x)", "???") + MySkip.testParse("identity(x) = x", "???") + MySkip.testParse("identity(x)", "???") }) describe("arrays", () => { - test("empty", () => expectParseToBe("[]", "[]")) - test("define", () => expectParseToBe("[0, 1, 2]", "[0, 1, 2]")) - test("define with strings", () => expectParseToBe("['hello', 'world']", "['hello', 'world']")) - skipTestParse("range(0, 4)", "range(0, 4)") - test("index", () => expectParseToBe("([0,1,2])[1]", "([0, 1, 2])[1]")) + testDescParse("empty", "[]", "[]") + testDescParse("define", "[0, 1, 2]", "[0, 1, 2]") + testDescParse("define with strings", "['hello', 'world']", "['hello', 'world']") + MySkip.testParse("range(0, 4)", "range(0, 4)") + testDescParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]") }) describe("records", () => { @@ -51,10 +57,10 @@ describe("MathJs parse", () => { }) describe("comments", () => { - skipDescTestParse("define", "# This is a comment", "???") + MySkip.testDescParse("define", "# This is a comment", "???") }) - describe("if statement", () => { - skipDescTestParse("define", "if (true) { 1 } else { 0 }", "???") + describe("if statement", () => { // TODO Tertiary operator instead + MySkip.testDescParse("define", "if (true) { 1 } else { 0 }", "???") }) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index a7539b7f..035ba7d9 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -42,6 +42,15 @@ describe("reducer using mathjs parse", () => { "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))", ) }) + describe("multi-line", () => { + testParseToBe("1; 2", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) 1) 2))") + testParseToBe("1+1; 2+1", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:add 1 1)) (:add 2 1)))") + }) + describe("assignment", () => { + testParseToBe("x=1; x", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x 1)) :x))") + testParseToBe("x=1+1; x+1", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x (:add 1 1))) (:add :x 1)))") + }) + }) describe("eval", () => { @@ -71,13 +80,26 @@ describe("eval", () => { test("index", () => expectEvalToBe("{a: 1}.a", "Ok(1)")) test("index not found", () => expectEvalToBe("{a: 1}.b", "Error(Record property not found: b)")) }) + + describe("multi-line", () => { + testEvalToBe("1; 2", "Error(Assignment expected)") + testEvalToBe("1+1; 2+1", "Error(Assignment expected)") + }) + describe("assignment", () => { + testEvalToBe("x=1; x", "Ok(1)") + testEvalToBe("x=1+1; x+1", "Ok(3)") + testEvalToBe("x=1; y=x+1; y+1", "Ok(3)") + testEvalToBe("1; x=1", "Error(Assignment expected)") + testEvalToBe("1; 1", "Error(Assignment expected)") + testEvalToBe("x=1; x=1", "Error(Expression expected)") + }) }) describe("test exceptions", () => { testDescEvalToBe( "javascript exception", - "jsraise('div by 0')", + "javascriptraise('div by 0')", "Error(JS Exception: Error: 'div by 0')", ) - testDescEvalToBe("rescript exception", "resraise()", "Error(TODO: unhandled rescript exception)") + testDescEvalToBe("rescript exception", "rescriptraise()", "Error(TODO: unhandled rescript exception)") }) diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index a968a156..6c920067 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -12,6 +12,7 @@ "test:watch": "jest --watchAll", "coverage": "rm -f *.coverage; yarn clean; BISECT_ENABLE=yes yarn build; yarn test; bisect-ppx-report html", "rescript:format": "find . -type f \\( -name '*.res' -o -name '*.resi' \\) -exec sh -c 'bsc -format {} | sponge {}' \\;", + "reducer:format": "find src/rescript/Reducer src/rescript/ReducerInterface -type f \\( -name '*.res' -o -name '*.resi' \\) -exec sh -c 'bsc -format {} | sponge {}' \\;", "all": "yarn build && yarn bundle && yarn test" }, "keywords": [ diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res index 824e36ef..01ce67cb 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res @@ -14,8 +14,8 @@ exception TestRescriptException let callInternal = (call: functionCall): result<'b, errorValue> => { let callMathJs = (call: functionCall): result<'b, errorValue> => switch call { - | ("jsraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests - | ("resraise", _) => raise(TestRescriptException) // For Tests + | ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests + | ("rescriptraise", _) => raise(TestRescriptException) // For Tests | call => call->toStringFunctionCall->MathJs.Eval.eval } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index 70601726..0e23bc99 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -1,8 +1,12 @@ type errorValue = | REArrayIndexNotFound(string, int) + | REAssignmentExpected + | REExpressionExpected | REFunctionExpected(string) | REJavaScriptExn(option, option) // Javascript Exception + | REMacroNotFound(string) | RERecordPropertyNotFound(string, string) + | RESymbolNotFound(string) | RESyntaxError(string) | RETodo(string) // To do @@ -11,6 +15,8 @@ type t = errorValue let errorToString = err => switch err { | REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}` + | REAssignmentExpected => "Assignment expected" + | REExpressionExpected => "Expression expected" | REFunctionExpected(msg) => `Function expected: ${msg}` | REJavaScriptExn(omsg, oname) => { let answer = "JS Exception:" @@ -24,7 +30,9 @@ let errorToString = err => } answer } + | REMacroNotFound(macro) => `Macro not found: ${macro}` | RERecordPropertyNotFound(msg, index) => `${msg}: ${index}` + | RESymbolNotFound(symbolName) => `${symbolName} is not defined` | RESyntaxError(desc) => `Syntax Error: ${desc}` | RETodo(msg) => `TODO: ${msg}` } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index 76e75e07..6aeaa81d 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res @@ -15,6 +15,7 @@ type t = expression */ let rec toString = expression => switch expression { + | T.EBindings(bindings) => "$$bound" | T.EList(aList) => `(${Belt.List.map(aList, aValue => toString(aValue)) ->Extra.List.interperse(" ") @@ -38,50 +39,137 @@ let parse_ = (expr: string, parser, converter): result => let parse = (mathJsCode: string): result => mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode) -module MapString = Belt.Map.String -type bindings = MapString.t -let defaultBindings: bindings = MapString.fromArray([]) -// TODO Define bindings for function execution context +let defaultBindings: T.bindings = Belt.Map.String.empty /* - After reducing each level of code tree, we have a value list to evaluate + Recursively evaluate/reduce the expression (Lisp AST) */ -let reduceValueList = (valueList: list): result => - switch valueList { - | list{EvSymbol(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch - | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok - } - -/* - Recursively evaluate/reduce the code tree -*/ -let rec reduceExpression = (expression: t, bindings): result => - switch expression { - | T.EValue(value) => value->Ok - | T.EList(list) => { - let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( - racc, - each: expression, - ) => - racc->Result.flatMap(acc => { - each - ->reduceExpression(bindings) - ->Result.flatMap(newNode => { - acc->Belt.List.add(newNode)->Ok - }) - }) - ) - racc->Result.flatMap(acc => acc->reduceValueList) +let rec reduceExpression = (expression: t, bindings: T.bindings): result => { + /* + After reducing each level of expression(Lisp AST), we have a value list to evaluate + */ + let reduceValueList = (valueList: list): result => + switch valueList { + | list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch + | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok } + + /* + Macros are like functions but instead of taking values as parameters, + they take expressions as parameters and return a new expression. + Macros are used to define language building blocks. They are like Lisp macros. + */ + let doMacroCall = (list: list, bindings: T.bindings): result => { + let dispatchMacroCall = (list: list, bindings: T.bindings): result => { + let rec replaceSymbols = (expression: t, bindings: T.bindings): result => + switch expression { + | T.EValue(EvSymbol(aSymbol)) => + switch bindings->Belt.Map.String.get(aSymbol) { + | Some(boundExpression) => boundExpression->Ok + | None => RESymbolNotFound(aSymbol)->Error + } + | T.EValue(_) => expression->Ok + | T.EBindings(_) => expression->Ok + | T.EList(list) => + list + ->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => + racc->Result.flatMap(acc => { + each + ->replaceSymbols(bindings) + ->Result.flatMap(newNode => { + acc->Belt.List.add(newNode)->Ok + }) + }) + ) + ->Result.map(acc => acc->T.EList) + } + + let doBindStatement = (statement: t, bindings: T.bindings) => { + switch statement { + | T.EList(list{T.EValue(EvCall("$let")), T.EValue(EvSymbol(aSymbol)), expression}) => { + let rNewExpression = replaceSymbols(expression, bindings) + rNewExpression->Result.map(newExpression => + Belt.Map.String.set(bindings, aSymbol, newExpression)->T.EBindings + ) + } + | _ => REAssignmentExpected->Error + } + } + + let doBindExpression = (expression: t, bindings: T.bindings) => { + switch expression { + | T.EList(list{T.EValue(EvCall("$let")), ..._}) => REExpressionExpected->Error + | _ => replaceSymbols(expression, bindings) + } + } + + switch list { + | list{T.EValue(EvCall("$$bindings"))} => bindings->EBindings->Ok + + | list{T.EValue(EvCall("$$bindStatement")), T.EBindings(bindings), statement} => + doBindStatement(statement, bindings) + | list{T.EValue(EvCall("$$bindExpression")), T.EBindings(bindings), expression} => + doBindExpression(expression, bindings) + | _ => list->T.EList->Ok + } + } + + list->dispatchMacroCall(bindings) } + let rec seekMacros = (expression: t, bindings: T.bindings): result => + switch expression { + | T.EValue(value) => expression->Ok + | T.EList(list) => { + let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( + racc, + each: expression, + ) => + racc->Result.flatMap(acc => { + each + ->seekMacros(bindings) + ->Result.flatMap(newNode => { + acc->Belt.List.add(newNode)->Ok + }) + }) + ) + racc->Result.flatMap(acc => acc->doMacroCall(bindings)) + } + } + + let rec reduceExpandedExpression = (expression: t): result => + switch expression { + | T.EValue(value) => value->Ok + | T.EList(list) => { + let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( + racc, + each: expression, + ) => + racc->Result.flatMap(acc => { + each + ->reduceExpandedExpression + ->Result.flatMap(newNode => { + acc->Belt.List.add(newNode)->Ok + }) + }) + ) + racc->Result.flatMap(acc => acc->reduceValueList) + } + } + + let rExpandedExpression: result = expression->seekMacros(bindings) + rExpandedExpression->Result.flatMap(expandedExpression => + expandedExpression->reduceExpandedExpression + ) +} + let evalWBindingsExpression = (aExpression, bindings): result => reduceExpression(aExpression, bindings) /* Evaluates MathJs code via Lisp using bindings and answers the result */ -let evalWBindings = (codeText: string, bindings: bindings) => { +let evalWBindings = (codeText: string, bindings: T.bindings) => { parse(codeText)->Result.flatMap(code => code->evalWBindingsExpression(bindings)) } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi deleted file mode 100644 index afd0105f..00000000 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi +++ /dev/null @@ -1,16 +0,0 @@ -module Result = Belt.Result -module T = Reducer_Expression_T -type expression = T.expression -type expressionValue = ReducerInterface.ExpressionValue.expressionValue -type t = expression -let toString: T.expression => Js.String.t -let toStringResult: result => string -let parse: string => result -module MapString = Belt.Map.String -type bindings = MapString.t -let defaultBindings: bindings -let reduceValueList: list => result -let reduceExpression: (expression, 'a) => result -let evalWBindingsExpression: (expression, 'a) => result -let evalWBindings: (string, bindings) => Result.t -let eval: string => Result.t diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res index 5f376050..fe938316 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_T.res @@ -1,5 +1,15 @@ open ReducerInterface.ExpressionValue +/* + An expression is a Lisp AST. An expression is either a primitive value or a list of expressions. + In the case of a list of expressions (e1, e2, e3, ...eN), the semantic is + apply e1, e2 -> apply e3 -> ... -> apply eN + This is Lisp semantics. It holds true in both eager and lazy evaluations. + A Lisp AST contains only expressions/primitive values to apply to their left. + The act of defining the semantics of a functional language is to write it in terms of Lisp AST. +*/ type rec expression = | EList(list) // A list to map-reduce | EValue(expressionValue) // Irreducible built-in value. Reducer should not know the internals. External libraries are responsible + | EBindings(bindings) // let/def kind of statements return bindings +and bindings = Belt.Map.String.t diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res index 7f20bacf..e3e2955c 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res @@ -12,17 +12,16 @@ type blockNode = {...node, "blocks": array} //conditionalNode type constantNode = {...node, "value": unit} //functionAssignmentNode -type functionNode = {...node, "fn": string, "args": array} type indexNode = {...node, "dimensions": array} type objectNode = {...node, "properties": Js.Dict.t} -type accessorNode = {...node, "object": node, "index": indexNode} -type operatorNode = {...functionNode, "op": string} +type accessorNode = {...node, "object": node, "index": indexNode, "name": string} -//parenthesisNode type parenthesisNode = {...node, "content": node} //rangeNode //relationalNode type symbolNode = {...node, "name": string} +type functionNode = {...node, "fn": unit, "args": array} +type operatorNode = {...functionNode, "op": string} type assignmentNode = {...node, "object": symbolNode, "value": node} type assignmentNodeWAccessor = {...node, "object": accessorNode, "value": node} type assignmentNodeWIndex = {...assignmentNodeWAccessor, "index": Js.null} @@ -93,6 +92,18 @@ let castNodeType = (node: node) => { } } +external unitAsSymbolNode: unit => symbolNode = "%identity" +external unitAsString: unit => string = "%identity" + +let nameOfFunctionNode = (fNode: functionNode): string => { + let name = fNode["fn"] + if Js.typeof(name) == "string" { + name->unitAsString + } else { + (name->unitAsSymbolNode)["name"] + } +} + let rec toString = (mathJsNode: mathJsNode): string => { let toStringValue = (a: 'a): string => if Js.typeof(a) == "string" { @@ -108,7 +119,7 @@ let rec toString = (mathJsNode: mathJsNode): string => { ->Js.String.concatMany("") let toStringFunctionNode = (fnode: functionNode): string => - `${fnode["fn"]}(${fnode["args"]->toStringNodeArray})` + `${fnode->nameOfFunctionNode}(${fnode["args"]->toStringNodeArray})` let toStringObjectEntry = ((key: string, value: node)): string => `${key}: ${value->toStringMathJsNode}` diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res index edd0313b..30c8651d 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_MathJs/Reducer_MathJs_ToExpression.res @@ -1,11 +1,11 @@ module ErrorValue = Reducer_ErrorValue module ExpressionValue = ReducerInterface.ExpressionValue -module ExtressionT = Reducer_Expression_T +module ExpressionT = Reducer_Expression_T module JavaScript = Reducer_Js module Parse = Reducer_MathJs_Parse module Result = Belt.Result -type expression = ExtressionT.expression +type expression = ExpressionT.expression type expressionValue = ExpressionValue.expressionValue type errorValue = ErrorValue.errorValue @@ -18,10 +18,19 @@ let rec fromNode = (mathJsNode: Parse.node): result => ) ) - let castFunctionNode = fNode => { - let fn = fNode["fn"]->ExpressionValue.EvSymbol->ExtressionT.EValue + let toEvCallValue = (name: string): expression => + name->ExpressionValue.EvCall->ExpressionT.EValue + let toEvSymbolValue = (name: string): expression => + name->ExpressionValue.EvSymbol->ExpressionT.EValue + + let passToFunction = (fName: string, rLispArgs): result => { + let fn = fName->toEvCallValue + rLispArgs->Result.flatMap(lispArgs => list{fn, ...lispArgs}->ExpressionT.EList->Ok) + } + + let caseFunctionNode = fNode => { let lispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList - lispArgs->Result.map(argsCode => list{fn, ...argsCode}->ExtressionT.EList) + passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs) } let caseObjectNode = oNode => { @@ -34,15 +43,16 @@ let rec fromNode = (mathJsNode: Parse.node): result => fromNode(value)->Result.map(valueExpression => { let entryCode = list{ - key->ExpressionValue.EvString->ExtressionT.EValue, + key->ExpressionValue.EvString->ExpressionT.EValue, valueExpression, - }->ExtressionT.EList + }->ExpressionT.EList list{entryCode, ...acc} }) ) ) - let lispName = "$constructRecord"->ExpressionValue.EvSymbol->ExtressionT.EValue - rargs->Result.map(args => list{lispName, ExtressionT.EList(args)}->ExtressionT.EList) + rargs->Result.flatMap(args => + passToFunction("$constructRecord", list{ExpressionT.EList(args)}->Ok) + ) // $consturctRecord gets a single argument: List of key-value paiers } oNode["properties"]->Js.Dict.entries->Belt.List.fromArray->fromObjectEntries @@ -60,30 +70,69 @@ let rec fromNode = (mathJsNode: Parse.node): result => }) ), ) - rpropertyCodeList->Result.map(propertyCodeList => ExtressionT.EList(propertyCodeList)) + rpropertyCodeList->Result.map(propertyCodeList => ExpressionT.EList(propertyCodeList)) } let caseAccessorNode = (objectNode, indexNode) => { - let fn = "$atIndex"->ExpressionValue.EvSymbol->ExtressionT.EValue - caseIndexNode(indexNode)->Result.flatMap(indexCode => { - fromNode(objectNode)->Result.map(objectCode => - list{fn, objectCode, indexCode}->ExtressionT.EList + fromNode(objectNode)->Result.flatMap(objectCode => + passToFunction("$atIndex", list{objectCode, indexCode}->Ok) ) }) } - switch typedMathJsNode { - | MjArrayNode(aNode) => - aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExtressionT.EList(list)) - | MjConstantNode(cNode) => - cNode["value"]->JavaScript.Gate.jsToEv->Result.map(v => v->ExtressionT.EValue) - | MjFunctionNode(fNode) => fNode->castFunctionNode - | MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->castFunctionNode - | MjParenthesisNode(pNode) => pNode["content"]->fromNode - | MjAccessorNode(aNode) => caseAccessorNode(aNode["object"], aNode["index"]) - | MjObjectNode(oNode) => caseObjectNode(oNode) - | MjSymbolNode(sNode) => sNode["name"]->ExpressionValue.EvSymbol->ExtressionT.EValue->Ok - | MjIndexNode(iNode) => caseIndexNode(iNode) + let caseAssignmentNode = aNode => { + let symbol = aNode["object"]["name"]->toEvSymbolValue + let rValueExpression = fromNode(aNode["value"]) + rValueExpression->Result.flatMap(valueExpression => { + let lispArgs = list{symbol, valueExpression}->Ok + passToFunction("$let", lispArgs) + }) } + + let caseArrayNode = aNode => { + aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list)) + } + + let caseBlockNode = (bNode): result => { + let blocks = bNode["blocks"] + let initialBindings = passToFunction("$$bindings", list{}->Ok) + let lastIndex = Belt.Array.length(blocks) - 1 + blocks->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, block, i) => { + rPreviousBindings->Result.flatMap(previousBindings => { + let node = block["node"] + let rStatement: result = node->fromNode + let bindName = if i == lastIndex { + "$$bindExpression" + } else { + "$$bindStatement" + } + rStatement->Result.flatMap((statement: expression) => { + let lispArgs = list{previousBindings, statement}->Ok + passToFunction(bindName, lispArgs) + }) + }) + }) + } + + let rFinalExpression: result = switch typedMathJsNode { + | MjAccessorNode(aNode) => caseAccessorNode(aNode["object"], aNode["index"]) + | MjArrayNode(aNode) => caseArrayNode(aNode) + | MjAssignmentNode(aNode) => caseAssignmentNode(aNode) + | MjSymbolNode(sNode) => { + let expr: expression = toEvSymbolValue(sNode["name"]) + let rExpr: result = expr->Ok + rExpr + } + | MjBlockNode(bNode) => caseBlockNode(bNode) + // | MjBlockNode(bNode) => "statement"->toEvSymbolValue->Ok + | MjConstantNode(cNode) => + cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok) + | MjFunctionNode(fNode) => fNode->caseFunctionNode + | MjIndexNode(iNode) => caseIndexNode(iNode) + | MjObjectNode(oNode) => caseObjectNode(oNode) + | MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->caseFunctionNode + | MjParenthesisNode(pNode) => pNode["content"]->fromNode + } + rFinalExpression }) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 10ac33aa..064f2db3 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -6,19 +6,21 @@ module Extra_Array = Reducer_Extra_Array module ErrorValue = Reducer_ErrorValue type rec expressionValue = + | EvArray(array) | EvBool(bool) + | EvCall(string) // External function call + | EvDistribution(GenericDist_Types.genericDist) | EvNumber(float) + | EvRecord(Js.Dict.t) | EvString(string) | EvSymbol(string) - | EvArray(array) - | EvRecord(Js.Dict.t) - | EvDistribution(GenericDist_Types.genericDist) type functionCall = (string, array) let rec toString = aValue => switch aValue { | EvBool(aBool) => Js.String.make(aBool) + | EvCall(fName) => `:${fName}` | EvNumber(aNumber) => Js.String.make(aNumber) | EvString(aString) => `'${aString}'` | EvSymbol(aString) => `:${aString}` @@ -39,12 +41,13 @@ let rec toString = aValue => ->Js.String.concatMany("") `{${pairs}}` } - | EvDistribution(dist) => `${GenericDist.toString(dist)}` + | EvDistribution(dist) => GenericDist.toString(dist) } let toStringWithType = aValue => switch aValue { | EvBool(_) => `Bool::${toString(aValue)}` + | EvCall(_) => `Call::${toString(aValue)}` | EvNumber(_) => `Number::${toString(aValue)}` | EvString(_) => `String::${toString(aValue)}` | EvSymbol(_) => `Symbol::${toString(aValue)}` From 87116d12d58b138047c2525c554db0bd4e1115c4 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 11 Apr 2022 16:51:15 +0200 Subject: [PATCH 10/33] reformat --- .../ReducerInterface/ReducerInterface_GenericDistribution.res | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index ea65b963..ed40e5d7 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -128,7 +128,8 @@ let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option< | ("mean", [EvDistribution(dist)]) => Helpers.toFloatFn(#Mean, dist) | ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist) | ("toSparkline", [EvDistribution(dist)]) => Helpers.toStringFn(ToSparkline(20), dist) - | ("toSparkline", [EvDistribution(dist), EvNumber(n)]) => Helpers.toStringFn(ToSparkline(Belt.Float.toInt(n)), dist) + | ("toSparkline", [EvDistribution(dist), EvNumber(n)]) => + Helpers.toStringFn(ToSparkline(Belt.Float.toInt(n)), dist) | ("exp", [EvDistribution(a)]) => // https://mathjs.org/docs/reference/functions/exp.html Helpers.twoDiststoDistFn(Algebraic, "pow", GenericDist.fromFloat(Math.e), a)->Some From f0008c1e206fccb98775f6d7e30c8646672a677e Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 11 Apr 2022 16:51:44 +0200 Subject: [PATCH 11/33] offer reducer:format as an example --- packages/squiggle-lang/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index a2c93a54..28d8aaa1 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -11,6 +11,7 @@ "test": "jest", "test:watch": "jest --watchAll", "coverage": "rm -f *.coverage; yarn clean; BISECT_ENABLE=yes yarn build; yarn test; bisect-ppx-report html", + "reducer:format": "find src/rescript/Reducer src/rescript/ReducerInterface -type f \\( -name '*.res' -o -name '*.resi' \\) -exec sh -c 'bsc -format {} | sponge {}' \\;", "all": "yarn build && yarn bundle && yarn test" }, "keywords": [ From 811c3bd6e71b90425aca115284811411bbc30acc Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 11 Apr 2022 14:53:17 -0400 Subject: [PATCH 12/33] Update CONTRIBUTING to Added information from our decisions at our last meeting --- CONTRIBUTING.md | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3c17b1e7..a9327ce8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,3 +50,77 @@ See [here](https://github.com/NixOS/nixpkgs/issues/107375) # Pull request protocol Please work against `staging` branch. **Do not** work against `master`. Please do not merge without approval from some subset of Quinn, Sam, and Ozzie; they will be auto-pinged. + +# Code Quality +- Aim for at least 8/10* quality in ``/packages/squiggle-lang``, and 7/10 quality in ``/packages/components``. +- If you submit a PR that is under a 7, for some reason, describe the reasoning for this in the PR. + +* This quality score is subjective. + +# Rescript Style + +**Use `->` instead of `|>`** +Note: Our codebase used to use `|>`, so there's a lot of that in the system. We'll gradually change it. + +**Use `x -> y -> z` instead of `let foo = y(x); let bar = z(foo)`** + +**Don't use anonymous functions with over three lines** +Bad: +```rescript + foo + -> E.O.fmap(r => { + let a = 34; + let b = 35; + let c = 48; + r + a + b + c + } +``` +Good: +```rescript + let addingFn = (r => { + let a = 34; + let b = 35; + let c = 48; + r + a + b + c + } + foo -> addingFn +``` + +**Write out types for everything, even if there's an interface file** +We'll try this for one month (ending May 5, 2022), then revisit. + +**Use the Rescript optional default syntax** +Rescript is clever about function inputs. There's custom syntax for default and optional arguments. In the cases where this applies, use it. + +From https://rescript-lang.org/docs/manual/latest/function: +```rescript +// radius can be omitted +let drawCircle = (~color, ~radius=?, ()) => { + setColor(color) + switch radius { + | None => startAt(1, 1) + | Some(r_) => startAt(r_, r_) + } +} +``` + +**Use named arguments** +If a function is called externally (in a different file), and has either: +1. Two arguments of the same type +2. Three paramaters or more. + +**Module naming: Use x_y as module names** +For example: ``Myname__Myproject__Add.res``. Rescript/Ocaml both require files to have unique names, so long names are needed to keep different parts separate from each other. + +See [this page](https://dev.to/yawaramin/a-modular-ocaml-project-structure-1ikd) for more information. + +**Module naming: Don't rename modules** +We have some of this in the Reducer code, but generally discourage it. + +**Use interface files (.resi) for files with very public interfaces** + +### Recommended Rescript resources +- https://dev.to/yawaramin/a-modular-ocaml-project-structure-1ikd +- https://github.com/avohq/reasonml-code-style-guide +- https://cs.brown.edu/courses/cs017/content/docs/reasonml-style.pdf +- https://github.com/ostera/reason-design-patterns/ From 3c82a88c6a848e96ebd6fc99ac1f12beefe8c13d Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 11 Apr 2022 20:24:46 -0400 Subject: [PATCH 13/33] Update CONTRIBUTING.md --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a9327ce8..ab87bca7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,9 +110,9 @@ If a function is called externally (in a different file), and has either: 2. Three paramaters or more. **Module naming: Use x_y as module names** -For example: ``Myname__Myproject__Add.res``. Rescript/Ocaml both require files to have unique names, so long names are needed to keep different parts separate from each other. +For example: ``Myname_Myproject_Add.res``. Rescript/Ocaml both require files to have unique names, so long names are needed to keep different parts separate from each other. -See [this page](https://dev.to/yawaramin/a-modular-ocaml-project-structure-1ikd) for more information. +See [this page](https://dev.to/yawaramin/a-modular-ocaml-project-structure-1ikd) for more information. (Though note that they use two underscores, and we do one. We might refactor that later. **Module naming: Don't rename modules** We have some of this in the Reducer code, but generally discourage it. From 7a160ad4450b2b81c6bb1438bc2a925b5b953504 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Apr 2022 10:40:56 +0000 Subject: [PATCH 14/33] Bump @types/webpack from 4.41.32 to 5.28.0 Bumps [@types/webpack](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/webpack) from 4.41.32 to 5.28.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/webpack) --- updated-dependencies: - dependency-name: "@types/webpack" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- packages/components/package.json | 2 +- yarn.lock | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/components/package.json b/packages/components/package.json index 2cef6bee..333b785d 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -75,7 +75,7 @@ "@storybook/preset-create-react-app": "^4.1.0", "@storybook/react": "^6.4.20", "@types/styled-components": "^5.1.24", - "@types/webpack": "^4.41.32", + "@types/webpack": "^5.28.0", "react-codejar": "^1.1.2", "style-loader": "^3.3.1", "ts-loader": "^9.2.8", diff --git a/yarn.lock b/yarn.lock index c7b42e3c..c084a73f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4142,7 +4142,7 @@ "@types/source-list-map" "*" source-map "^0.7.3" -"@types/webpack@^4.41.26", "@types/webpack@^4.41.32", "@types/webpack@^4.41.8": +"@types/webpack@^4.41.26", "@types/webpack@^4.41.8": version "4.41.32" resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.32.tgz#a7bab03b72904070162b2f169415492209e94212" integrity sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg== @@ -4154,6 +4154,15 @@ anymatch "^3.0.0" source-map "^0.6.0" +"@types/webpack@^5.28.0": + version "5.28.0" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-5.28.0.tgz#78dde06212f038d77e54116cfe69e88ae9ed2c03" + integrity sha512-8cP0CzcxUiFuA9xGJkfeVpqmWTk9nx6CWwamRGCj95ph1SmlRRk9KlCZ6avhCbZd4L68LvYT6l1kpdEnQXrF8w== + dependencies: + "@types/node" "*" + tapable "^2.2.0" + webpack "^5" + "@types/ws@^8.5.1": version "8.5.3" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" @@ -17499,7 +17508,7 @@ webpack@4: watchpack "^1.7.4" webpack-sources "^1.4.1" -webpack@^5.64.4, webpack@^5.70.0, webpack@^5.72.0, webpack@^5.9.0: +webpack@^5, webpack@^5.64.4, webpack@^5.70.0, webpack@^5.72.0, webpack@^5.9.0: version "5.72.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.72.0.tgz#f8bc40d9c6bb489a4b7a8a685101d6022b8b6e28" integrity sha512-qmSmbspI0Qo5ld49htys8GY9XhS9CGqFoHTsOVAnjBdg0Zn79y135R+k4IR4rKK6+eKaabMhJwiVB7xw0SJu5w== From 4fe72b8fb416fee7336071143f99efa0a37d2c9e Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 12 Apr 2022 15:47:46 +0200 Subject: [PATCH 15/33] remove Reduce_Expression.rsi. Too many changes. Hot target. Preventing development --- .../Reducer_Expression.resi | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi deleted file mode 100644 index 2a6db9bd..00000000 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.resi +++ /dev/null @@ -1,29 +0,0 @@ -module Result = Belt.Result -module T = Reducer_Expression_T -type expression = T.expression -@genType -type expressionValue = ReducerInterface_ExpressionValue.expressionValue -type t = expression -let toString: T.expression => Js.String.t -let toStringResult: result => string -let parse: string => result -module MapString = Belt.Map.String -type bindings = MapString.t -let defaultBindings: bindings -let reduceValueList: list => result< - expressionValue, - Reducer_ErrorValue.t, -> -let reduceExpression: (expression, 'a) => result< - expressionValue, - Reducer_ErrorValue.t, -> -let evalWBindingsExpression: (expression, 'a) => result< - expressionValue, - Reducer_ErrorValue.t, -> -let evalWBindings: (string, bindings) => Result.t< - expressionValue, - Reducer_ErrorValue.t, -> -let eval: string => Result.t From f8fa47e9237042a433dfd7830ce1913599ebca94 Mon Sep 17 00:00:00 2001 From: Quinn Date: Tue, 12 Apr 2022 09:50:13 -0400 Subject: [PATCH 16/33] hotfix: `working_directory` in prettier action jobs were triggering too much. --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2926ee85..8b679a84 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,6 +59,7 @@ jobs: with: dry: true prettier_options: --check . + working_directory: packages/squiggle-lang lang-build-test-bundle: name: Language build, test, and bundle @@ -98,6 +99,7 @@ jobs: with: dry: true prettier_options: --check . + working_directory: packages/components components-bundle-build: name: Components bundle and build @@ -135,6 +137,7 @@ jobs: with: dry: true prettier_options: --check . + working_directory: packages/website website-build: name: Website build From e7e51d9582807b0b6436dbb74764e01b95b0c35d Mon Sep 17 00:00:00 2001 From: Quinn Date: Tue, 12 Apr 2022 09:54:57 -0400 Subject: [PATCH 17/33] hotfix: debugging workingdirectory --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b679a84..5c1dca23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: with: dry: true prettier_options: --check . - working_directory: packages/squiggle-lang + # working_directory: packages/squiggle-lang lang-build-test-bundle: name: Language build, test, and bundle @@ -91,7 +91,7 @@ jobs: defaults: run: shell: bash - working-directory: packages/components + # working-directory: packages/components steps: - uses: actions/checkout@v2 - name: Check javascript, typescript, and markdown lint @@ -129,7 +129,7 @@ jobs: defaults: run: shell: bash - working-directory: packages/website + # working-directory: packages/website steps: - uses: actions/checkout@v2 - name: Check javascript, typescript, and markdown lint From d45b5f3d72908e56083b7129e3c7ddf30ba87f49 Mon Sep 17 00:00:00 2001 From: Quinn Date: Tue, 12 Apr 2022 10:03:15 -0400 Subject: [PATCH 18/33] hotfix: working directory in lint jobs https://github.com/creyD/prettier_action/issues/90 --- .github/workflows/ci.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c1dca23..1358c2a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,8 +58,7 @@ jobs: uses: creyD/prettier_action@v4.2 with: dry: true - prettier_options: --check . - # working_directory: packages/squiggle-lang + prettier_options: --check packages/squiggle-lang lang-build-test-bundle: name: Language build, test, and bundle @@ -91,15 +90,14 @@ jobs: defaults: run: shell: bash - # working-directory: packages/components + working-directory: packages/components steps: - uses: actions/checkout@v2 - name: Check javascript, typescript, and markdown lint uses: creyD/prettier_action@v4.2 with: dry: true - prettier_options: --check . - working_directory: packages/components + prettier_options: --check packages/components components-bundle-build: name: Components bundle and build @@ -129,15 +127,14 @@ jobs: defaults: run: shell: bash - # working-directory: packages/website + working-directory: packages/website steps: - uses: actions/checkout@v2 - name: Check javascript, typescript, and markdown lint uses: creyD/prettier_action@v4.2 with: dry: true - prettier_options: --check . - working_directory: packages/website + prettier_options: --check packages/website website-build: name: Website build From 1707ae8d5ebe7b479bf163c5570fcae19fe879ba Mon Sep 17 00:00:00 2001 From: Quinn Date: Tue, 12 Apr 2022 10:11:15 -0400 Subject: [PATCH 19/33] hotfix: precise version `skip-duplicate-actions` --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1358c2a1..7a17556b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,17 +25,17 @@ jobs: steps: - id: skip_lang_check name: Check if the changes are about squiggle-lang src files - uses: fkirc/skip-duplicate-actions@master + uses: fkirc/skip-duplicate-actions@v3.4.1 with: paths: '["packages/squiggle-lang/**"]' - id: skip_components_check name: Check if the changes are about components src files - uses: fkirc/skip-duplicate-actions@master + uses: fkirc/skip-duplicate-actions@v3.4.1 with: paths: '["packages/components/**"]' - id: skip_website_check name: Check if the changes are about website src files - uses: fkirc/skip-duplicate-actions@master + uses: fkirc/skip-duplicate-actions@v3.4.1 with: paths: '["packages/website/**"]' From 05b5efce1895304e1a2c165bb3b61105a8c777f5 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 12 Apr 2022 16:15:27 +0200 Subject: [PATCH 20/33] remove -> in switch cases. close umuro/squiggle#59 squiggle --- .../Reducer_Expression/Reducer_Expression.res | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index 6aeaa81d..ee1495d9 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res @@ -70,18 +70,18 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result expression->Ok | T.EBindings(_) => expression->Ok - | T.EList(list) => - list - ->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => - racc->Result.flatMap(acc => { - each - ->replaceSymbols(bindings) - ->Result.flatMap(newNode => { - acc->Belt.List.add(newNode)->Ok + | T.EList(list) => { + let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => + racc->Result.flatMap(acc => { + each + ->replaceSymbols(bindings) + ->Result.flatMap(newNode => { + acc->Belt.List.add(newNode)->Ok + }) }) - }) - ) - ->Result.map(acc => acc->T.EList) + ) + racc->Result.map(acc => acc->T.EList) + } } let doBindStatement = (statement: t, bindings: T.bindings) => { From a95cdfabe340475ad2ac940a550a2e571367a647 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 12 Apr 2022 16:19:50 +0200 Subject: [PATCH 21/33] dont use short Desc - close umuro/squiggle#51 --- .../Reducer_MathJsParse_test.res | 20 +++++++++---------- .../__tests__/Reducer/Reducer_test.res | 18 ++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index fce588f1..879e20f9 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -9,12 +9,12 @@ let expectParseToBe = (expr, answer) => let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testDescParse = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) +let testDescriptionParse = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) module MySkip = { let testParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) - let testDescParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) + let testDescriptionParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) } describe("MathJs parse", () => { @@ -44,23 +44,23 @@ describe("MathJs parse", () => { }) describe("arrays", () => { - testDescParse("empty", "[]", "[]") - testDescParse("define", "[0, 1, 2]", "[0, 1, 2]") - testDescParse("define with strings", "['hello', 'world']", "['hello', 'world']") + testDescriptionParse("empty", "[]", "[]") + testDescriptionParse("define", "[0, 1, 2]", "[0, 1, 2]") + testDescriptionParse("define with strings", "['hello', 'world']", "['hello', 'world']") MySkip.testParse("range(0, 4)", "range(0, 4)") - testDescParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]") + testDescriptionParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]") }) describe("records", () => { - testDescParse("define", "{a: 1, b: 2}", "{a: 1, b: 2}") - testDescParse("use", "record.property", "record['property']") + testDescriptionParse("define", "{a: 1, b: 2}", "{a: 1, b: 2}") + testDescriptionParse("use", "record.property", "record['property']") }) describe("comments", () => { - MySkip.testDescParse("define", "# This is a comment", "???") + MySkip.testDescriptionParse("define", "# This is a comment", "???") }) describe("if statement", () => { // TODO Tertiary operator instead - MySkip.testDescParse("define", "if (true) { 1 } else { 0 }", "???") + MySkip.testDescriptionParse("define", "if (true) { 1 } else { 0 }", "???") }) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 035ba7d9..8e65328b 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -3,11 +3,11 @@ open Reducer_TestHelpers let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testDescParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) +let testDescriptionParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) -let testDescEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer)) +let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer)) describe("reducer using mathjs parse", () => { // Test the MathJs parser compatibility @@ -29,14 +29,14 @@ describe("reducer using mathjs parse", () => { //Note. () is a empty list in Lisp // The only builtin structure in Lisp is list. There are no arrays // [1,2,3] becomes (1 2 3) - testDescParseToBe("empty", "[]", "Ok(())") + testDescriptionParseToBe("empty", "[]", "Ok(())") testParseToBe("[1, 2, 3]", "Ok((1 2 3))") testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))") - testDescParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))") + testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))") }) describe("records", () => { - testDescParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") - testDescParseToBe( + testDescriptionParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") + testDescriptionParseToBe( "use", "{a: 1, b: 2}.a", "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))", @@ -73,7 +73,7 @@ describe("eval", () => { testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])") testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])") testEvalToBe("([0,1,2])[1]", "Ok(1)") - testDescEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)") + testDescriptionEvalToBe("index not found", "([0,1,2])[10]", "Error(Array index not found: 10)") }) describe("records", () => { test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1, b: 2})")) @@ -96,10 +96,10 @@ describe("eval", () => { }) describe("test exceptions", () => { - testDescEvalToBe( + testDescriptionEvalToBe( "javascript exception", "javascriptraise('div by 0')", "Error(JS Exception: Error: 'div by 0')", ) - testDescEvalToBe("rescript exception", "rescriptraise()", "Error(TODO: unhandled rescript exception)") + testDescriptionEvalToBe("rescript exception", "rescriptraise()", "Error(TODO: unhandled rescript exception)") }) From 1b4422bb906e41067e1aef6541115ec9ebcedf54 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 12 Apr 2022 16:26:43 +0200 Subject: [PATCH 22/33] revise lisp references - close umuro/squiggle#50 --- .../Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res | 2 +- .../Reducer/Reducer_Expression/Reducer_Expression.res | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res index 01ce67cb..21c91dc2 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res @@ -58,7 +58,7 @@ let callInternal = (call: functionCall): result<'b, errorValue> => { } /* - Lisp engine uses Result monad while reducing expressions + Reducer uses Result monad while reducing expressions */ let dispatch = (call: functionCall): result => try { diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index ee1495d9..8498c294 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res @@ -11,7 +11,7 @@ type expressionValue = ExpressionValue.expressionValue type t = expression /* - Shows the Lisp Code as text lisp code + Shows the expression as text of expression */ let rec toString = expression => switch expression { @@ -31,7 +31,7 @@ let toStringResult = codeResult => } /* - Converts a MathJs code to Lisp Code + Converts a MathJs code to expression */ let parse_ = (expr: string, parser, converter): result => expr->parser->Result.flatMap(node => converter(node)) @@ -167,13 +167,13 @@ let evalWBindingsExpression = (aExpression, bindings): result { parse(codeText)->Result.flatMap(code => code->evalWBindingsExpression(bindings)) } /* - Evaluates MathJs code via Lisp and answers the result + Evaluates MathJs code via Reducer and answers the result */ let eval = (code: string) => evalWBindings(code, defaultBindings) From d1ea15e4f938c357db11da0bf7086b574e15351c Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 12 Apr 2022 17:12:19 +0200 Subject: [PATCH 23/33] fix ts export --- packages/squiggle-lang/src/js/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 8455c601..1a53aa6c 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -117,6 +117,8 @@ function createTsExport( ); case "EvBool": return tag("boolean", x.value); + case "EvCall": + return tag("call", x.value); case "EvDistribution": return tag("distribution", new Distribution(x.value, sampEnv)); case "EvNumber": From 15d1e789cc13b2a3af80f3cd20d862d8d1569eb2 Mon Sep 17 00:00:00 2001 From: Quinn Date: Tue, 12 Apr 2022 14:57:52 -0400 Subject: [PATCH 24/33] Update CODEOWNERS --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b7dcbd2d..531dec44 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,8 +9,8 @@ # This also holds true for GitHub teams. # Rescript -*.res @Hazelfire @OAGr @quinn-dougherty -*.resi @Hazelfire @OAGr @quinn-dougherty +*.res @OAGr @quinn-dougherty +*.resi @OAGr @quinn-dougherty # Typescript *.tsx @Hazelfire @OAGr From 5d8c2bfc966d1b65e26170433b72e9118b642bd7 Mon Sep 17 00:00:00 2001 From: Quinn Date: Tue, 12 Apr 2022 15:00:47 -0400 Subject: [PATCH 25/33] Update CONTRIBUTING.md --- CONTRIBUTING.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cbd35bd6..155907d8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,13 @@ See [here](https://github.com/NixOS/nixpkgs/issues/107375) # Pull request protocol -Please work against `staging` branch. **Do not** work against `master`. Please do not merge without approval from some subset of Quinn, Sam, and Ozzie; they will be auto-pinged. +Please work against `develop` branch. **Do not** work against `master`. + +- For rescript code: Quinn and Ozzie are reviewers +- For js or typescript code: Sam and Ozzie are reviewers +- For ops code (i.e. yaml, package.json): Quinn and Sam are reviewers + +Autopings are set up: if you are not autopinged, you are welcome to comment, but please do not use the formal review feature, send approvals, rejections, or merges. # Code Quality - Aim for at least 8/10* quality in ``/packages/squiggle-lang``, and 7/10 quality in ``/packages/components``. From d9faab26807be24e8740d19e856121ff3f590c0b Mon Sep 17 00:00:00 2001 From: Quinn Date: Tue, 12 Apr 2022 15:01:22 -0400 Subject: [PATCH 26/33] Update CODEOWNERS --- .github/CODEOWNERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 531dec44..22ba334f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -21,9 +21,9 @@ # Any opsy files .github/* @quinn-dougherty -*.json @quinn-dougherty @Hazelfire -*.y*ml @quinn-dougherty -*.config.js @Hazelfire +*.json @quinn-dougherty @Hazelfire @OAGr +*.y*ml @quinn-dougherty @OAGr +*.config.js @Hazelfire @OAGr # Documentation *.md @quinn-dougherty @OAGr @Hazelfire From 1092550c897094914ef68dfd649f0969a42ca1ac Mon Sep 17 00:00:00 2001 From: Quinn Date: Tue, 12 Apr 2022 15:18:35 -0400 Subject: [PATCH 27/33] Update CODEOWNERS --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 22ba334f..ca57d333 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,10 +17,10 @@ *.ts @Hazelfire @OAGr # Javascript -*.js @Hazelfire +*.js @Hazelfire @OAGr # Any opsy files -.github/* @quinn-dougherty +.github/** @quinn-dougherty @OAGr *.json @quinn-dougherty @Hazelfire @OAGr *.y*ml @quinn-dougherty @OAGr *.config.js @Hazelfire @OAGr From fea990de2d314187f166c24e62ddb56230eea5dd Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Wed, 13 Apr 2022 01:34:06 +0200 Subject: [PATCH 28/33] Sam's patch PR#226 --- packages/squiggle-lang/src/js/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 1a53aa6c..4b8cddab 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -88,6 +88,7 @@ function tag(x: a, y: b): tagged { export type squiggleExpression = | tagged<"symbol", string> | tagged<"string", string> + | tagged<"call", string> | tagged<"array", squiggleExpression[]> | tagged<"boolean", boolean> | tagged<"distribution", Distribution> From f2f885f269bb2ec4b96f3a8fc957825dbb780f36 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Wed, 13 Apr 2022 10:07:33 +1000 Subject: [PATCH 29/33] Hotfix Typescript checker failing --- CONTRIBUTING.md | 24 ++++++++++++------- .../src/rescript/TypescriptInterface.res | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 155907d8..f90fa60b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,7 @@ See [here](https://github.com/NixOS/nixpkgs/issues/107375) # Pull request protocol -Please work against `develop` branch. **Do not** work against `master`. +Please work against `develop` branch. **Do not** work against `master`. - For rescript code: Quinn and Ozzie are reviewers - For js or typescript code: Sam and Ozzie are reviewers @@ -60,7 +60,8 @@ Please work against `develop` branch. **Do not** work against `master`. Autopings are set up: if you are not autopinged, you are welcome to comment, but please do not use the formal review feature, send approvals, rejections, or merges. # Code Quality -- Aim for at least 8/10* quality in ``/packages/squiggle-lang``, and 7/10 quality in ``/packages/components``. + +- Aim for at least 8/10\* quality in `/packages/squiggle-lang`, and 7/10 quality in `/packages/components`. - If you submit a PR that is under a 7, for some reason, describe the reasoning for this in the PR. * This quality score is subjective. @@ -74,6 +75,7 @@ Note: Our codebase used to use `|>`, so there's a lot of that in the system. We' **Don't use anonymous functions with over three lines** Bad: + ```rescript foo -> E.O.fmap(r => { @@ -83,7 +85,9 @@ Bad: r + a + b + c } ``` + Good: + ```rescript let addingFn = (r => { let a = 34; @@ -101,6 +105,7 @@ We'll try this for one month (ending May 5, 2022), then revisit. Rescript is clever about function inputs. There's custom syntax for default and optional arguments. In the cases where this applies, use it. From https://rescript-lang.org/docs/manual/latest/function: + ```rescript // radius can be omitted let drawCircle = (~color, ~radius=?, ()) => { @@ -114,22 +119,23 @@ let drawCircle = (~color, ~radius=?, ()) => { **Use named arguments** If a function is called externally (in a different file), and has either: + 1. Two arguments of the same type 2. Three paramaters or more. **Module naming: Use x_y as module names** -For example: ``Myname_Myproject_Add.res``. Rescript/Ocaml both require files to have unique names, so long names are needed to keep different parts separate from each other. +For example: `Myname_Myproject_Add.res`. Rescript/Ocaml both require files to have unique names, so long names are needed to keep different parts separate from each other. See [this page](https://dev.to/yawaramin/a-modular-ocaml-project-structure-1ikd) for more information. (Though note that they use two underscores, and we do one. We might refactor that later. **Module naming: Don't rename modules** -We have some of this in the Reducer code, but generally discourage it. +We have some of this in the Reducer code, but generally discourage it. **Use interface files (.resi) for files with very public interfaces** -### Recommended Rescript resources -- https://dev.to/yawaramin/a-modular-ocaml-project-structure-1ikd -- https://github.com/avohq/reasonml-code-style-guide -- https://cs.brown.edu/courses/cs017/content/docs/reasonml-style.pdf -- https://github.com/ostera/reason-design-patterns/ +### Recommended Rescript resources +- https://dev.to/yawaramin/a-modular-ocaml-project-structure-1ikd +- https://github.com/avohq/reasonml-code-style-guide +- https://cs.brown.edu/courses/cs017/content/docs/reasonml-style.pdf +- https://github.com/ostera/reason-design-patterns/ diff --git a/packages/squiggle-lang/src/rescript/TypescriptInterface.res b/packages/squiggle-lang/src/rescript/TypescriptInterface.res index a706bdd2..2683edb1 100644 --- a/packages/squiggle-lang/src/rescript/TypescriptInterface.res +++ b/packages/squiggle-lang/src/rescript/TypescriptInterface.res @@ -32,7 +32,7 @@ let makeSampleSetDist = SampleSetDist.make let evaluate = Reducer.evaluate @genType -type expressionValue = Reducer_Expression.expressionValue +type expressionValue = ReducerInterface_ExpressionValue.expressionValue @genType type errorValue = Reducer_ErrorValue.errorValue From e234951d622be1dbc96a7e07a6328786be67e72c Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Wed, 13 Apr 2022 10:14:11 +1000 Subject: [PATCH 30/33] Hotfix bundle failure --- packages/squiggle-lang/src/rescript/Reducer/Reducer.resi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi index b5b811e6..6f6a55a8 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi @@ -6,7 +6,7 @@ module Js = Reducer_Js module MathJs = Reducer_MathJs @genType -type expressionValue = Reducer_Expression.expressionValue +type expressionValue = ReducerInterface_ExpressionValue.expressionValue @genType let evaluate: string => result From 4f95c019eb8ea5a1bc1333a248c1fd1806d0f345 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Tue, 12 Apr 2022 19:59:40 -0400 Subject: [PATCH 31/33] `yarn format` --- .../__tests__/Bandwidth_test.res | 4 +- .../Distributions/GenericDist_Fixtures.res | 4 +- .../__tests__/Distributions/Mixture_test.res | 109 +++++------ .../Distributions/SampleSetDist_test.res | 1 - .../__tests__/Distributions/Symbolic_test.res | 173 ++++++++---------- .../squiggle-lang/__tests__/Lodash_test.res | 4 +- .../Reducer_Dispatch_BuiltIn_test.res | 3 +- .../Reducer_MathJsParse_test.res | 6 +- .../__tests__/Reducer/Reducer_test.res | 25 ++- .../ReducerInterface_Distribution_test.res | 6 +- .../squiggle-lang/__tests__/TestHelpers.res | 13 +- .../squiggle-lang/__tests__/XYShape_test.res | 10 +- .../DistributionOperation.resi | 101 +++++----- .../Distributions/DistributionTypes.res | 6 +- .../GenericDist/GenericDist_Types.res | 2 +- .../AlgebraicShapeCombination.res | 1 - .../Distributions/PointSetDist/Continuous.res | 12 +- .../Distributions/PointSetDist/Mixed.res | 3 +- .../PointSetDist/PointSetDist.res | 2 +- .../PointSetDist/PointSetTypes.res | 8 +- .../SymbolicDist/SymbolicDist.res | 8 +- .../src/rescript/OldInterpreter/AST.res | 2 +- .../typeSystem/HardcodedFunctions.res | 18 +- .../OldInterpreter/typeSystem/TypeSystem.res | 12 +- .../squiggle-lang/src/rescript/Utility/E.res | 13 +- .../src/rescript/Utility/Jstat.res | 17 +- 26 files changed, 282 insertions(+), 281 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Bandwidth_test.res b/packages/squiggle-lang/__tests__/Bandwidth_test.res index 4e5c630a..df621743 100644 --- a/packages/squiggle-lang/__tests__/Bandwidth_test.res +++ b/packages/squiggle-lang/__tests__/Bandwidth_test.res @@ -4,10 +4,10 @@ open Expect describe("Bandwidth", () => { test("nrd0()", () => { let data = [1., 4., 3., 2.] - expect(SampleSetDist_Bandwidth.nrd0(data)) -> toEqual(0.7625801874014622) + expect(SampleSetDist_Bandwidth.nrd0(data))->toEqual(0.7625801874014622) }) test("nrd()", () => { let data = [1., 4., 3., 2.] - expect(SampleSetDist_Bandwidth.nrd(data)) -> toEqual(0.8981499984950554) + expect(SampleSetDist_Bandwidth.nrd(data))->toEqual(0.8981499984950554) }) }) diff --git a/packages/squiggle-lang/__tests__/Distributions/GenericDist_Fixtures.res b/packages/squiggle-lang/__tests__/Distributions/GenericDist_Fixtures.res index 05f0981b..2a71c942 100644 --- a/packages/squiggle-lang/__tests__/Distributions/GenericDist_Fixtures.res +++ b/packages/squiggle-lang/__tests__/Distributions/GenericDist_Fixtures.res @@ -6,6 +6,8 @@ let normalDist: GenericDist_Types.genericDist = normalDist5 let betaDist: GenericDist_Types.genericDist = Symbolic(#Beta({alpha: 2.0, beta: 5.0})) let lognormalDist: GenericDist_Types.genericDist = Symbolic(#Lognormal({mu: 0.0, sigma: 1.0})) let cauchyDist: GenericDist_Types.genericDist = Symbolic(#Cauchy({local: 1.0, scale: 1.0})) -let triangularDist: GenericDist_Types.genericDist = Symbolic(#Triangular({low: 1.0, medium: 2.0, high: 3.0})) +let triangularDist: GenericDist_Types.genericDist = Symbolic( + #Triangular({low: 1.0, medium: 2.0, high: 3.0}), +) let exponentialDist: GenericDist_Types.genericDist = Symbolic(#Exponential({rate: 2.0})) let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0})) diff --git a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res index 2ab1de08..14859ff0 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Mixture_test.res @@ -1,70 +1,73 @@ open Jest -open Expect -open TestHelpers +open Expect +open TestHelpers -// TODO: use Normal.make (etc.), but preferably after the new validation dispatch is in. +// TODO: use Normal.make (etc.), but preferably after the new validation dispatch is in. let mkNormal = (mean, stdev) => GenericDist_Types.Symbolic(#Normal({mean: mean, stdev: stdev})) let mkBeta = (alpha, beta) => GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta})) let mkExponential = rate => GenericDist_Types.Symbolic(#Exponential({rate: rate})) -let mkUniform = (low, high) => GenericDist_Types.Symbolic(#Uniform({low: low, high: high})) +let mkUniform = (low, high) => GenericDist_Types.Symbolic(#Uniform({low: low, high: high})) let mkCauchy = (local, scale) => GenericDist_Types.Symbolic(#Cauchy({local: local, scale: scale})) let mkLognormal = (mu, sigma) => GenericDist_Types.Symbolic(#Lognormal({mu: mu, sigma: sigma})) describe("mixture", () => { - testAll("fair mean of two normal distributions", list{(0.0, 1e2), (-1e1, -1e-4), (-1e1, 1e2), (-1e1, 1e1)}, tup => { // should be property - let (mean1, mean2) = tup - let meanValue = { - run(Mixture([(mkNormal(mean1, 9e-1), 0.5), (mkNormal(mean2, 9e-1), 0.5)])) - -> outputMap(FromDist(ToFloat(#Mean))) - } - meanValue -> unpackFloat -> expect -> toBeSoCloseTo((mean1 +. mean2) /. 2.0, ~digits=-1) - }) testAll( - "weighted mean of a beta and an exponential", - // This would not survive property testing, it was easy for me to find cases that NaN'd out. - list{((128.0, 1.0), 2.0), ((2e-1, 64.0), 16.0), ((1e0, 1e0), 64.0)}, - tup => { - let ((alpha, beta), rate) = tup - let betaWeight = 0.25 - let exponentialWeight = 0.75 - let meanValue = { - run(Mixture( - [ - (mkBeta(alpha, beta), betaWeight), - (mkExponential(rate), exponentialWeight) - ] - )) -> outputMap(FromDist(ToFloat(#Mean))) - } - let betaMean = 1.0 /. (1.0 +. beta /. alpha) - let exponentialMean = 1.0 /. rate - meanValue - -> unpackFloat - -> expect - -> toBeSoCloseTo( - betaWeight *. betaMean +. exponentialWeight *. exponentialMean, - ~digits=-1 + "fair mean of two normal distributions", + list{(0.0, 1e2), (-1e1, -1e-4), (-1e1, 1e2), (-1e1, 1e1)}, + tup => { + // should be property + let (mean1, mean2) = tup + let meanValue = { + run(Mixture([(mkNormal(mean1, 9e-1), 0.5), (mkNormal(mean2, 9e-1), 0.5)]))->outputMap( + FromDist(ToFloat(#Mean)), ) } + meanValue->unpackFloat->expect->toBeSoCloseTo((mean1 +. mean2) /. 2.0, ~digits=-1) + }, ) testAll( - "weighted mean of lognormal and uniform", - // Would not survive property tests: very easy to find cases that NaN out. - list{((-1e2,1e1), (2e0,1e0)), ((-1e-16,1e-16), (1e-8,1e0)), ((0.0,1e0), (1e0,1e-2))}, - tup => { - let ((low, high), (mu, sigma)) = tup - let uniformWeight = 0.6 - let lognormalWeight = 0.4 - let meanValue = { - run(Mixture([(mkUniform(low, high), uniformWeight), (mkLognormal(mu, sigma), lognormalWeight)])) - -> outputMap(FromDist(ToFloat(#Mean))) - } - let uniformMean = (low +. high) /. 2.0 - let lognormalMean = mu +. sigma ** 2.0 /. 2.0 - meanValue - -> unpackFloat - -> expect - -> toBeSoCloseTo(uniformWeight *. uniformMean +. lognormalWeight *. lognormalMean, ~digits=-1) + "weighted mean of a beta and an exponential", + // This would not survive property testing, it was easy for me to find cases that NaN'd out. + list{((128.0, 1.0), 2.0), ((2e-1, 64.0), 16.0), ((1e0, 1e0), 64.0)}, + tup => { + let ((alpha, beta), rate) = tup + let betaWeight = 0.25 + let exponentialWeight = 0.75 + let meanValue = { + run( + Mixture([(mkBeta(alpha, beta), betaWeight), (mkExponential(rate), exponentialWeight)]), + )->outputMap(FromDist(ToFloat(#Mean))) } + let betaMean = 1.0 /. (1.0 +. beta /. alpha) + let exponentialMean = 1.0 /. rate + meanValue + ->unpackFloat + ->expect + ->toBeSoCloseTo(betaWeight *. betaMean +. exponentialWeight *. exponentialMean, ~digits=-1) + }, + ) + testAll( + "weighted mean of lognormal and uniform", + // Would not survive property tests: very easy to find cases that NaN out. + list{((-1e2, 1e1), (2e0, 1e0)), ((-1e-16, 1e-16), (1e-8, 1e0)), ((0.0, 1e0), (1e0, 1e-2))}, + tup => { + let ((low, high), (mu, sigma)) = tup + let uniformWeight = 0.6 + let lognormalWeight = 0.4 + let meanValue = { + run( + Mixture([ + (mkUniform(low, high), uniformWeight), + (mkLognormal(mu, sigma), lognormalWeight), + ]), + )->outputMap(FromDist(ToFloat(#Mean))) + } + let uniformMean = (low +. high) /. 2.0 + let lognormalMean = mu +. sigma ** 2.0 /. 2.0 + meanValue + ->unpackFloat + ->expect + ->toBeSoCloseTo(uniformWeight *. uniformMean +. lognormalWeight *. lognormalMean, ~digits=-1) + }, ) }) - diff --git a/packages/squiggle-lang/__tests__/Distributions/SampleSetDist_test.res b/packages/squiggle-lang/__tests__/Distributions/SampleSetDist_test.res index 5a48dd80..ee36d191 100644 --- a/packages/squiggle-lang/__tests__/Distributions/SampleSetDist_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/SampleSetDist_test.res @@ -38,4 +38,3 @@ describe("Continuous and discrete splits", () => { let toArr2 = discrete2 |> E.FloatFloatMap.toArray makeTest("splitMedium at count=500", toArr2 |> Belt.Array.length, 500) }) - diff --git a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res index 9a37a63a..d99d86c6 100644 --- a/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res +++ b/packages/squiggle-lang/__tests__/Distributions/Symbolic_test.res @@ -9,125 +9,109 @@ describe("(Symbolic) normalize", () => { testAll("has no impact on normal distributions", list{-1e8, -1e-2, 0.0, 1e-4, 1e16}, mean => { let normalValue = mkNormal(mean, 2.0) let normalizedValue = run(FromDist(ToDist(Normalize), normalValue)) - normalizedValue - -> unpackDist - -> expect - -> toEqual(normalValue) + normalizedValue->unpackDist->expect->toEqual(normalValue) }) }) describe("(Symbolic) mean", () => { testAll("of normal distributions", list{-1e8, -16.0, -1e-2, 0.0, 1e-4, 32.0, 1e16}, mean => { - run(FromDist(ToFloat(#Mean), mkNormal(mean, 4.0))) - -> unpackFloat - -> expect - -> toBeCloseTo(mean) + run(FromDist(ToFloat(#Mean), mkNormal(mean, 4.0)))->unpackFloat->expect->toBeCloseTo(mean) }) Skip.test("of normal(0, -1) (it NaNs out)", () => { - run(FromDist(ToFloat(#Mean), mkNormal(1e1, -1e0))) - -> unpackFloat - -> expect - -> ExpectJs.toBeFalsy + run(FromDist(ToFloat(#Mean), mkNormal(1e1, -1e0)))->unpackFloat->expect->ExpectJs.toBeFalsy }) test("of normal(0, 1e-8) (it doesn't freak out at tiny stdev)", () => { - run(FromDist(ToFloat(#Mean), mkNormal(0.0, 1e-8))) - -> unpackFloat - -> expect - -> toBeCloseTo(0.0) + run(FromDist(ToFloat(#Mean), mkNormal(0.0, 1e-8)))->unpackFloat->expect->toBeCloseTo(0.0) }) testAll("of exponential distributions", list{1e-7, 2.0, 10.0, 100.0}, rate => { - let meanValue = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Exponential({rate: rate})))) - meanValue -> unpackFloat -> expect -> toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median + let meanValue = run( + FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Exponential({rate: rate}))), + ) + meanValue->unpackFloat->expect->toBeCloseTo(1.0 /. rate) // https://en.wikipedia.org/wiki/Exponential_distribution#Mean,_variance,_moments,_and_median }) test("of a cauchy distribution", () => { - let meanValue = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0})))) - meanValue - -> unpackFloat - -> expect - -> toBeCloseTo(2.01868297874546) + let meanValue = run( + FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Cauchy({local: 1.0, scale: 1.0}))), + ) + meanValue->unpackFloat->expect->toBeCloseTo(2.01868297874546) //-> toBe(GenDistError(Other("Cauchy distributions may have no mean value."))) }) - testAll("of triangular distributions", list{(1.0,2.0,3.0), (-1e7,-1e-7,1e-7), (-1e-7,1e0,1e7), (-1e-16,0.0,1e-16)}, tup => { - let (low, medium, high) = tup - let meanValue = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Triangular({low: low, medium: medium, high: high})) - )) - meanValue - -> unpackFloat - -> expect - -> toBeCloseTo((low +. medium +. high) /. 3.0) // https://www.statology.org/triangular-distribution/ - }) + testAll( + "of triangular distributions", + list{(1.0, 2.0, 3.0), (-1e7, -1e-7, 1e-7), (-1e-7, 1e0, 1e7), (-1e-16, 0.0, 1e-16)}, + tup => { + let (low, medium, high) = tup + let meanValue = run( + FromDist( + ToFloat(#Mean), + GenericDist_Types.Symbolic(#Triangular({low: low, medium: medium, high: high})), + ), + ) + meanValue->unpackFloat->expect->toBeCloseTo((low +. medium +. high) /. 3.0) // https://www.statology.org/triangular-distribution/ + }, + ) - // TODO: nonpositive inputs are SUPPOSED to crash. - testAll("of beta distributions", list{(1e-4, 6.4e1), (1.28e2, 1e0), (1e-16, 1e-16), (1e16, 1e16), (-1e4, 1e1), (1e1, -1e4)}, tup => { - let (alpha, beta) = tup - let meanValue = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta})) - )) - meanValue - -> unpackFloat - -> expect - -> toBeCloseTo(1.0 /. (1.0 +. (beta /. alpha))) // https://en.wikipedia.org/wiki/Beta_distribution#Mean - }) + // TODO: nonpositive inputs are SUPPOSED to crash. + testAll( + "of beta distributions", + list{(1e-4, 6.4e1), (1.28e2, 1e0), (1e-16, 1e-16), (1e16, 1e16), (-1e4, 1e1), (1e1, -1e4)}, + tup => { + let (alpha, beta) = tup + let meanValue = run( + FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Beta({alpha: alpha, beta: beta}))), + ) + meanValue->unpackFloat->expect->toBeCloseTo(1.0 /. (1.0 +. beta /. alpha)) // https://en.wikipedia.org/wiki/Beta_distribution#Mean + }, + ) // TODO: When we have our theory of validators we won't want this to be NaN but to be an error. test("of beta(0, 0)", () => { - let meanValue = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Beta({alpha: 0.0, beta: 0.0})) - )) - meanValue - -> unpackFloat - -> expect - -> ExpectJs.toBeFalsy + let meanValue = run( + FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Beta({alpha: 0.0, beta: 0.0}))), + ) + meanValue->unpackFloat->expect->ExpectJs.toBeFalsy }) - testAll("of lognormal distributions", list{(2.0, 4.0), (1e-7, 1e-2), (-1e6, 10.0), (1e3, -1e2), (-1e8, -1e4), (1e2, 1e-5)}, tup => { - let (mu, sigma) = tup - let meanValue = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Lognormal({mu: mu, sigma: sigma})) - )) - meanValue - -> unpackFloat - -> expect - -> toBeCloseTo(Js.Math.exp(mu +. sigma ** 2.0 /. 2.0 )) // https://brilliant.org/wiki/log-normal-distribution/ - }) + testAll( + "of lognormal distributions", + list{(2.0, 4.0), (1e-7, 1e-2), (-1e6, 10.0), (1e3, -1e2), (-1e8, -1e4), (1e2, 1e-5)}, + tup => { + let (mu, sigma) = tup + let meanValue = run( + FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Lognormal({mu: mu, sigma: sigma}))), + ) + meanValue->unpackFloat->expect->toBeCloseTo(Js.Math.exp(mu +. sigma ** 2.0 /. 2.0)) // https://brilliant.org/wiki/log-normal-distribution/ + }, + ) - testAll("of uniform distributions", list{(1e-5, 12.345), (-1e4, 1e4), (-1e16, -1e2), (5.3e3, 9e9)}, tup => { - let (low, high) = tup - let meanValue = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Uniform({low: low, high: high})) - )) - meanValue - -> unpackFloat - -> expect - -> toBeCloseTo((low +. high) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments - }) + testAll( + "of uniform distributions", + list{(1e-5, 12.345), (-1e4, 1e4), (-1e16, -1e2), (5.3e3, 9e9)}, + tup => { + let (low, high) = tup + let meanValue = run( + FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Uniform({low: low, high: high}))), + ) + meanValue->unpackFloat->expect->toBeCloseTo((low +. high) /. 2.0) // https://en.wikipedia.org/wiki/Continuous_uniform_distribution#Moments + }, + ) test("of a float", () => { - let meanValue = run(FromDist( - ToFloat(#Mean), - GenericDist_Types.Symbolic(#Float(7.7)) - )) - meanValue -> unpackFloat -> expect -> toBeCloseTo(7.7) + let meanValue = run(FromDist(ToFloat(#Mean), GenericDist_Types.Symbolic(#Float(7.7)))) + meanValue->unpackFloat->expect->toBeCloseTo(7.7) }) }) describe("Normal distribution with sparklines", () => { - let parameterWiseAdditionPdf = (n1: SymbolicDistTypes.normal, n2: SymbolicDistTypes.normal) => { let normalDistAtSumMeanConstr = SymbolicDist.Normal.add(n1, n2) let normalDistAtSumMean: SymbolicDistTypes.normal = switch normalDistAtSumMeanConstr { - | #Normal(params) => params + | #Normal(params) => params } x => SymbolicDist.Normal.pdf(x, normalDistAtSumMean) } @@ -138,24 +122,25 @@ describe("Normal distribution with sparklines", () => { test("mean=5 pdf", () => { let pdfNormalDistAtMean5 = x => SymbolicDist.Normal.pdf(x, normalDistAtMean5) - let sparklineMean5 = fnImage(pdfNormalDistAtMean5, range20Float) - Sparklines.create(sparklineMean5, ()) - -> expect - -> toEqual(`▁▂▃▆██▇▅▂▁▁▁▁▁▁▁▁▁▁▁`) + let sparklineMean5 = fnImage(pdfNormalDistAtMean5, range20Float) + Sparklines.create(sparklineMean5, ()) + ->expect + ->toEqual(`▁▂▃▆██▇▅▂▁▁▁▁▁▁▁▁▁▁▁`) }) - - test("parameter-wise addition of two normal distributions", () => { - let sparklineMean15 = normalDistAtMean5 -> parameterWiseAdditionPdf(normalDistAtMean10) -> fnImage(range20Float) + + test("parameter-wise addition of two normal distributions", () => { + let sparklineMean15 = + normalDistAtMean5->parameterWiseAdditionPdf(normalDistAtMean10)->fnImage(range20Float) Sparklines.create(sparklineMean15, ()) - -> expect - -> toEqual(`▁▁▁▁▁▁▁▁▁▂▃▄▆███▇▅▄▂`) + ->expect + ->toEqual(`▁▁▁▁▁▁▁▁▁▂▃▄▆███▇▅▄▂`) }) test("mean=10 cdf", () => { let cdfNormalDistAtMean10 = x => SymbolicDist.Normal.cdf(x, normalDistAtMean10) let sparklineMean10 = fnImage(cdfNormalDistAtMean10, range20Float) Sparklines.create(sparklineMean10, ()) - -> expect - -> toEqual(`▁▁▁▁▁▁▁▁▂▄▅▇████████`) + ->expect + ->toEqual(`▁▁▁▁▁▁▁▁▂▄▅▇████████`) }) }) diff --git a/packages/squiggle-lang/__tests__/Lodash_test.res b/packages/squiggle-lang/__tests__/Lodash_test.res index 2700764b..f0782019 100644 --- a/packages/squiggle-lang/__tests__/Lodash_test.res +++ b/packages/squiggle-lang/__tests__/Lodash_test.res @@ -3,8 +3,8 @@ open Expect let makeTest = (~only=false, str, item1, item2) => only - ? Only.test(str, () => expect(item1) -> toEqual(item2)) - : test(str, () => expect(item1) -> toEqual(item2)) + ? Only.test(str, () => expect(item1)->toEqual(item2)) + : test(str, () => expect(item1)->toEqual(item2)) describe("Lodash", () => describe("Lodash", () => { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res index 438d78e5..f376094a 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res @@ -6,8 +6,7 @@ open Expect let expectEvalToBe = (expr: string, answer: string) => Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer) -let testEval = (expr, answer) => - test(expr, () => expectEvalToBe(expr, answer)) +let testEval = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) describe("builtin", () => { // All MathJs operators and functions are available for string, number and boolean diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res index 879e20f9..6282c14d 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res @@ -14,7 +14,8 @@ let testDescriptionParse = (desc, expr, answer) => test(desc, () => expectParseT module MySkip = { let testParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) - let testDescriptionParse = (desc, expr, answer) => Skip.test(desc, () => expectParseToBe(expr, answer)) + let testDescriptionParse = (desc, expr, answer) => + Skip.test(desc, () => expectParseToBe(expr, answer)) } describe("MathJs parse", () => { @@ -60,7 +61,8 @@ describe("MathJs parse", () => { MySkip.testDescriptionParse("define", "# This is a comment", "???") }) - describe("if statement", () => { // TODO Tertiary operator instead + describe("if statement", () => { + // TODO Tertiary operator instead MySkip.testDescriptionParse("define", "if (true) { 1 } else { 0 }", "???") }) }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 8e65328b..bd9101a2 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -3,7 +3,8 @@ open Reducer_TestHelpers let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testDescriptionParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) +let testDescriptionParseToBe = (desc, expr, answer) => + test(desc, () => expectParseToBe(expr, answer)) let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answer)) @@ -44,13 +45,21 @@ describe("reducer using mathjs parse", () => { }) describe("multi-line", () => { testParseToBe("1; 2", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) 1) 2))") - testParseToBe("1+1; 2+1", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:add 1 1)) (:add 2 1)))") + testParseToBe( + "1+1; 2+1", + "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:add 1 1)) (:add 2 1)))", + ) }) describe("assignment", () => { - testParseToBe("x=1; x", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x 1)) :x))") - testParseToBe("x=1+1; x+1", "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x (:add 1 1))) (:add :x 1)))") + testParseToBe( + "x=1; x", + "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x 1)) :x))", + ) + testParseToBe( + "x=1+1; x+1", + "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :x (:add 1 1))) (:add :x 1)))", + ) }) - }) describe("eval", () => { @@ -101,5 +110,9 @@ describe("test exceptions", () => { "javascriptraise('div by 0')", "Error(JS Exception: Error: 'div by 0')", ) - testDescriptionEvalToBe("rescript exception", "rescriptraise()", "Error(TODO: unhandled rescript exception)") + testDescriptionEvalToBe( + "rescript exception", + "rescriptraise()", + "Error(TODO: unhandled rescript exception)", + ) }) diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res index 096ac360..cc17593a 100644 --- a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res +++ b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res @@ -111,7 +111,11 @@ describe("parse on distribution functions", () => { }) describe("pointwise arithmetic expressions", () => { testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))") - testParse(~skip=true, "normal(5,2) .- normal(5,1)", "Ok((:dotSubtract (:normal 5 2) (:normal 5 1)))") + testParse( + ~skip=true, + "normal(5,2) .- normal(5,1)", + "Ok((:dotSubtract (:normal 5 2) (:normal 5 1)))", + ) testParse("normal(5,2) .* normal(5,1)", "Ok((:dotMultiply (:normal 5 2) (:normal 5 1)))") testParse("normal(5,2) ./ normal(5,1)", "Ok((:dotDivide (:normal 5 2) (:normal 5 1)))") testParse("normal(5,2) .^ normal(5,1)", "Ok((:dotPow (:normal 5 2) (:normal 5 1)))") diff --git a/packages/squiggle-lang/__tests__/TestHelpers.res b/packages/squiggle-lang/__tests__/TestHelpers.res index a61f57d0..09199fc1 100644 --- a/packages/squiggle-lang/__tests__/TestHelpers.res +++ b/packages/squiggle-lang/__tests__/TestHelpers.res @@ -3,9 +3,8 @@ open Expect let makeTest = (~only=false, str, item1, item2) => only - ? Only.test(str, () => expect(item1) -> toEqual(item2)) - : test(str, () => expect(item1) -> toEqual(item2)) - + ? Only.test(str, () => expect(item1)->toEqual(item2)) + : test(str, () => expect(item1)->toEqual(item2)) let {toFloat, toDist, toString, toError, fmap} = module(DistributionOperation.Output) @@ -20,7 +19,9 @@ let run = DistributionOperation.run(~env) let outputMap = fmap(~env) let unreachableInTestFileMessage = "Should be impossible to reach (This error is in test file)" let toExtFloat: option => float = E.O.toExt(unreachableInTestFileMessage) -let toExtDist: option => GenericDist_Types.genericDist = E.O.toExt(unreachableInTestFileMessage) +let toExtDist: option => GenericDist_Types.genericDist = E.O.toExt( + unreachableInTestFileMessage, +) // let toExt: option<'a> => 'a = E.O.toExt(unreachableInTestFileMessage) -let unpackFloat = x => x -> toFloat -> toExtFloat -let unpackDist = y => y -> toDist -> toExtDist +let unpackFloat = x => x->toFloat->toExtFloat +let unpackDist = y => y->toDist->toExtDist diff --git a/packages/squiggle-lang/__tests__/XYShape_test.res b/packages/squiggle-lang/__tests__/XYShape_test.res index b4a693b5..701d82e1 100644 --- a/packages/squiggle-lang/__tests__/XYShape_test.res +++ b/packages/squiggle-lang/__tests__/XYShape_test.res @@ -3,8 +3,8 @@ open Expect let makeTest = (~only=false, str, item1, item2) => only - ? Only.test(str, () => expect(item1) -> toEqual(item2)) - : test(str, () => expect(item1) -> toEqual(item2)) + ? Only.test(str, () => expect(item1)->toEqual(item2)) + : test(str, () => expect(item1)->toEqual(item2)) let pointSetDist1: PointSetTypes.xyShape = {xs: [1., 4., 8.], ys: [0.2, 0.4, 0.8]} @@ -21,7 +21,11 @@ let pointSetDist3: PointSetTypes.xyShape = { describe("XYShapes", () => { describe("logScorePoint", () => { makeTest("When identical", XYShape.logScorePoint(30, pointSetDist1, pointSetDist1), Some(0.0)) - makeTest("When similar", XYShape.logScorePoint(30, pointSetDist1, pointSetDist2), Some(1.658971191043856)) + makeTest( + "When similar", + XYShape.logScorePoint(30, pointSetDist1, pointSetDist2), + Some(1.658971191043856), + ) makeTest( "When very different", XYShape.logScorePoint(30, pointSetDist1, pointSetDist3), diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi index bfe45013..e4f7759f 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionOperation/DistributionOperation.resi @@ -39,57 +39,52 @@ module Output: { } module Constructors: { - @genType - let mean: (~env: env, genericDist) => result - @genType - let sample: (~env: env, genericDist) => result - @genType - let cdf: (~env: env, genericDist, float) => result - @genType - let inv: (~env: env, genericDist, float) => result - @genType - let pdf: (~env: env, genericDist, float) => result - @genType - let normalize: (~env: env, genericDist) => result - @genType - let toPointSet: (~env: env, genericDist) => result - @genType - let toSampleSet: (~env: env, genericDist, int) => result - @genType - let truncate: ( - ~env: env, - genericDist, - option, - option, - ) => result - @genType - let inspect: (~env: env, genericDist) => result - @genType - let toString: (~env: env, genericDist) => result - @genType - let toSparkline: (~env: env, genericDist, int) => result - @genType - let algebraicAdd: (~env: env, genericDist, genericDist) => result - @genType - let algebraicMultiply: (~env: env, genericDist, genericDist) => result - @genType - let algebraicDivide: (~env: env, genericDist, genericDist) => result - @genType - let algebraicSubtract: (~env: env, genericDist, genericDist) => result - @genType - let algebraicLogarithm: (~env: env, genericDist, genericDist) => result - @genType - let algebraicPower: (~env: env, genericDist, genericDist) => result - @genType - let pointwiseAdd: (~env: env, genericDist, genericDist) => result - @genType - let pointwiseMultiply: (~env: env, genericDist, genericDist) => result - @genType - let pointwiseDivide: (~env: env, genericDist, genericDist) => result - @genType - let pointwiseSubtract: (~env: env, genericDist, genericDist) => result - @genType - let pointwiseLogarithm: (~env: env, genericDist, genericDist) => result - @genType - let pointwisePower: (~env: env, genericDist, genericDist) => result + @genType + let mean: (~env: env, genericDist) => result + @genType + let sample: (~env: env, genericDist) => result + @genType + let cdf: (~env: env, genericDist, float) => result + @genType + let inv: (~env: env, genericDist, float) => result + @genType + let pdf: (~env: env, genericDist, float) => result + @genType + let normalize: (~env: env, genericDist) => result + @genType + let toPointSet: (~env: env, genericDist) => result + @genType + let toSampleSet: (~env: env, genericDist, int) => result + @genType + let truncate: (~env: env, genericDist, option, option) => result + @genType + let inspect: (~env: env, genericDist) => result + @genType + let toString: (~env: env, genericDist) => result + @genType + let toSparkline: (~env: env, genericDist, int) => result + @genType + let algebraicAdd: (~env: env, genericDist, genericDist) => result + @genType + let algebraicMultiply: (~env: env, genericDist, genericDist) => result + @genType + let algebraicDivide: (~env: env, genericDist, genericDist) => result + @genType + let algebraicSubtract: (~env: env, genericDist, genericDist) => result + @genType + let algebraicLogarithm: (~env: env, genericDist, genericDist) => result + @genType + let algebraicPower: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseAdd: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseMultiply: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseDivide: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseSubtract: (~env: env, genericDist, genericDist) => result + @genType + let pointwiseLogarithm: (~env: env, genericDist, genericDist) => result + @genType + let pointwisePower: (~env: env, genericDist, genericDist) => result } diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res index cab58839..389af699 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res @@ -55,7 +55,11 @@ module DistributionOperation = { type fromDist = | ToFloat(Operation.toFloat) | ToDist(toDist) - | ToDistCombination(Operation.direction, Operation.arithmeticOperation, [#Dist(genericDist) | #Float(float)]) + | ToDistCombination( + Operation.direction, + Operation.arithmeticOperation, + [#Dist(genericDist) | #Float(float)], + ) | ToString type singleParamaterFunction = diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res index 4d2ba9b6..df8d9dbc 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist/GenericDist_Types.res @@ -15,7 +15,7 @@ module Error = { type t = error let fromString = (s: string): t => Other(s) - + @genType let toString = (x: t) => { switch x { diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res index 70440878..f8740de9 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/AlgebraicShapeCombination.res @@ -100,7 +100,6 @@ let combineShapesContinuousContinuous = ( s1: PointSetTypes.xyShape, s2: PointSetTypes.xyShape, ): PointSetTypes.xyShape => { - // if we add the two distributions, we should probably use normal filters. // if we multiply the two distributions, we should probably use lognormal filters. let t1m = toDiscretePointMassesFromTriangulars(s1) diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res index aa27fb62..4c48df70 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Continuous.res @@ -235,18 +235,10 @@ module T = Dist({ let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 2.0 /. 2.0 let indefiniteIntegralLinear = (p, a, b) => a *. p ** 2.0 /. 2.0 +. b *. p ** 3.0 /. 3.0 - Analysis.integrate( - ~indefiniteIntegralStepwise, - ~indefiniteIntegralLinear, - t, - ) + Analysis.integrate(~indefiniteIntegralStepwise, ~indefiniteIntegralLinear, t) } let variance = (t: t): float => - XYShape.Analysis.getVarianceDangerously( - t, - mean, - Analysis.getMeanOfSquares, - ) + XYShape.Analysis.getVarianceDangerously(t, mean, Analysis.getMeanOfSquares) }) let downsampleEquallyOverX = (length, t): t => diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res index e05bd408..9e27057a 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/Mixed.res @@ -212,8 +212,7 @@ module T = Dist({ let totalIntegralSum = discreteIntegralSum +. continuousIntegralSum let getMeanOfSquares = ({discrete, continuous}: t) => { - let discreteMean = - discrete |> Discrete.shapeMap(XYShape.T.square) |> Discrete.T.mean + let discreteMean = discrete |> Discrete.shapeMap(XYShape.T.square) |> Discrete.T.mean let continuousMean = continuous |> Continuous.Analysis.getMeanOfSquares (discreteMean *. discreteIntegralSum +. continuousMean *. continuousIntegralSum) /. totalIntegralSum diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res index f3f3c20c..d0668a57 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetDist.res @@ -207,4 +207,4 @@ let toSparkline = (t: t, bucketCount) => T.toContinuous(t) ->E.O2.fmap(Continuous.downsampleEquallyOverX(bucketCount)) ->E.O2.toResult("toContinous Error: Could not convert into continuous distribution") - ->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create()) \ No newline at end of file + ->E.R2.fmap(r => Continuous.getShape(r).ys->Sparklines.create()) diff --git a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res index 4de2e880..a1a02a67 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/PointSetDist/PointSetTypes.res @@ -14,10 +14,10 @@ type distributionType = [ | #CDF ] -type xyShape = XYShape.xyShape; -type interpolationStrategy = XYShape.interpolationStrategy; -type extrapolationStrategy = XYShape.extrapolationStrategy; -type interpolator = XYShape.extrapolationStrategy; +type xyShape = XYShape.xyShape +type interpolationStrategy = XYShape.interpolationStrategy +type extrapolationStrategy = XYShape.extrapolationStrategy +type interpolator = XYShape.extrapolationStrategy @genType type rec continuousShape = { diff --git a/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res index f2c1e886..e1d01390 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SymbolicDist/SymbolicDist.res @@ -81,7 +81,7 @@ module Triangular = { low < medium && medium < high ? Ok(#Triangular({low: low, medium: medium, high: high})) : Error("Triangular values must be increasing order.") - let pdf = (x, t: t) => Jstat.Triangular.pdf(x, t.low, t.high, t.medium) // not obvious in jstat docs that high comes before medium? + let pdf = (x, t: t) => Jstat.Triangular.pdf(x, t.low, t.high, t.medium) // not obvious in jstat docs that high comes before medium? let cdf = (x, t: t) => Jstat.Triangular.cdf(x, t.low, t.high, t.medium) let inv = (p, t: t) => Jstat.Triangular.inv(p, t.low, t.high, t.medium) let sample = (t: t) => Jstat.Triangular.sample(t.low, t.high, t.medium) @@ -346,7 +346,11 @@ module T = { | _ => #NoSolution } - let toPointSetDist = (~xSelection=#ByWeight, sampleCount, d: symbolicDist): PointSetTypes.pointSetDist => + let toPointSetDist = ( + ~xSelection=#ByWeight, + sampleCount, + d: symbolicDist, + ): PointSetTypes.pointSetDist => switch d { | #Float(v) => Discrete(Discrete.make(~integralSumCache=Some(1.0), {xs: [v], ys: [1.0]})) | _ => diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/AST.res b/packages/squiggle-lang/src/rescript/OldInterpreter/AST.res index 2dca6ffc..569912c3 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/AST.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/AST.res @@ -21,4 +21,4 @@ let toPointSetDist = (samplingInputs, environment, node: node) => let runFunction = (samplingInputs, environment, inputs, fn: ASTTypes.Function.t) => { let params = envs(samplingInputs, environment) ASTTypes.Function.run(params, inputs, fn) -} \ No newline at end of file +} diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res index 8302b532..0c2dde67 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/HardcodedFunctions.res @@ -22,7 +22,7 @@ let makeSymbolicFromTwoFloats = (name, fn) => ~inputTypes=[#Float, #Float], ~run=x => switch x { - | [#Float(a), #Float(b)] => fn(a, b) |> E.R.fmap(r => (#SymbolicDist(r))) + | [#Float(a), #Float(b)] => fn(a, b) |> E.R.fmap(r => #SymbolicDist(r)) | e => wrongInputsError(e) }, (), @@ -90,7 +90,8 @@ let floatFromDist = ( switch t { | #SymbolicDist(s) => SymbolicDist.T.operate(distToFloatOp, s) |> E.R.bind(_, v => Ok(#SymbolicDist(#Float(v)))) - | #RenderedDist(rs) => PointSetDist.operate(distToFloatOp, rs) |> (v => Ok(#SymbolicDist(#Float(v)))) + | #RenderedDist(rs) => + PointSetDist.operate(distToFloatOp, rs) |> (v => Ok(#SymbolicDist(#Float(v)))) } let verticalScaling = (scaleOp, rs, scaleBy) => { @@ -125,10 +126,15 @@ module Multimodal = { ->E.R.bind(TypeSystem.TypedValue.toArray) ->E.R.bind(r => r |> E.A.fmap(TypeSystem.TypedValue.toFloat) |> E.A.R.firstErrorOrOpen) - E.R.merge(dists, weights) -> E.R.bind(((a, b)) => - E.A.length(b) > E.A.length(a) ? - Error("Too many weights provided") : - Ok(E.A.zipMaxLength(a, b) |> E.A.fmap(((a, b)) => (a |> E.O.toExn(""), b |> E.O.default(1.0)))) + E.R.merge(dists, weights)->E.R.bind(((a, b)) => + E.A.length(b) > E.A.length(a) + ? Error("Too many weights provided") + : Ok( + E.A.zipMaxLength(a, b) |> E.A.fmap(((a, b)) => ( + a |> E.O.toExn(""), + b |> E.O.default(1.0), + )), + ) ) | _ => Error("Needs items") } diff --git a/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/TypeSystem.res b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/TypeSystem.res index 51332106..32cc9e1b 100644 --- a/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/TypeSystem.res +++ b/packages/squiggle-lang/src/rescript/OldInterpreter/typeSystem/TypeSystem.res @@ -86,11 +86,7 @@ module TypedValue = { |> E.R.fmap(r => #Array(r)) | (#Hash(named), #Hash(r)) => let keyValues = - named |> E.A.fmap(((name, intendedType)) => ( - name, - intendedType, - Hash.getByName(r, name), - )) + named |> E.A.fmap(((name, intendedType)) => (name, intendedType, Hash.getByName(r, name))) let typedHash = keyValues |> E.A.fmap(((name, intendedType, optionNode)) => @@ -180,11 +176,7 @@ module Function = { _coerceInputNodes(evaluationParams, t.inputTypes, t.shouldCoerceTypes), ) - let run = ( - evaluationParams: ASTTypes.evaluationParams, - inputNodes: inputNodes, - t: t, - ) => + let run = (evaluationParams: ASTTypes.evaluationParams, inputNodes: inputNodes, t: t) => inputsToTypedValues(evaluationParams, inputNodes, t)->E.R.bind(t.run) |> ( x => diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 16d87896..2f834c50 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -179,14 +179,15 @@ module R = { } module R2 = { - let fmap = (a,b) => R.fmap(b,a) - let bind = (a, b) => R.bind(b, a) + 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, map) => switch(a){ + let errMap = (a, map) => + switch a { | Ok(r) => Ok(r) | Error(e) => map(e) - } + } } let safe_fn_of_string = (fn, s: string): option<'a> => @@ -300,7 +301,6 @@ module A = { |> Rationale.Result.return } - // This zips while taking the longest elements of each array. let zipMaxLength = (array1, array2) => { let maxLength = Int.max(length(array1), length(array2)) @@ -456,7 +456,6 @@ module A = { let diff = (arr: array): array => Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left) - exception RangeError(string) let range = (min: float, max: float, n: int): array => switch n { @@ -474,7 +473,7 @@ module A = { } module A2 = { - let fmap = (a,b) => A.fmap(b,a) + let fmap = (a, b) => A.fmap(b, a) let joinWith = (a, b) => A.joinWith(b, a) } diff --git a/packages/squiggle-lang/src/rescript/Utility/Jstat.res b/packages/squiggle-lang/src/rescript/Utility/Jstat.res index 0fc31d6d..03c43174 100644 --- a/packages/squiggle-lang/src/rescript/Utility/Jstat.res +++ b/packages/squiggle-lang/src/rescript/Utility/Jstat.res @@ -36,8 +36,8 @@ module Exponential = { @module("jstat") @scope("exponential") external pdf: (float, float) => float = "pdf" @module("jstat") @scope("exponential") external cdf: (float, float) => float = "cdf" @module("jstat") @scope("exponential") external inv: (float, float) => float = "inv" - @module("jstat") @scope("exponential") external sample: (float) => float = "sample" - @module("jstat") @scope("exponential") external mean: (float) => float = "mean" + @module("jstat") @scope("exponential") external sample: float => float = "sample" + @module("jstat") @scope("exponential") external mean: float => float = "mean" } module Cauchy = { @@ -56,7 +56,6 @@ module Triangular = { @module("jstat") @scope("triangular") external mean: (float, float, float) => float = "mean" } - module Pareto = { @module("jstat") @scope("pareto") external pdf: (float, float, float) => float = "pdf" @module("jstat") @scope("pareto") external cdf: (float, float, float) => float = "cdf" @@ -66,20 +65,20 @@ module Pareto = { module Poisson = { @module("jstat") @scope("poisson") external pdf: (float, float) => float = "pdf" @module("jstat") @scope("poisson") external cdf: (float, float) => float = "cdf" - @module("jstat") @scope("poisson") external sample: (float) => float = "sample" - @module("jstat") @scope("poisson") external mean: (float) => float = "mean" + @module("jstat") @scope("poisson") external sample: float => float = "sample" + @module("jstat") @scope("poisson") external mean: float => float = "mean" } module Weibull = { @module("jstat") @scope("weibull") external pdf: (float, float, float) => float = "pdf" - @module("jstat") @scope("weibull") external cdf: (float, float,float ) => float = "cdf" - @module("jstat") @scope("weibull") external sample: (float,float) => float = "sample" - @module("jstat") @scope("weibull") external mean: (float,float) => float = "mean" + @module("jstat") @scope("weibull") external cdf: (float, float, float) => float = "cdf" + @module("jstat") @scope("weibull") external sample: (float, float) => float = "sample" + @module("jstat") @scope("weibull") external mean: (float, float) => float = "mean" } module Binomial = { @module("jstat") @scope("binomial") external pdf: (float, float, float) => float = "pdf" - @module("jstat") @scope("binomial") external cdf: (float, float,float ) => float = "cdf" + @module("jstat") @scope("binomial") external cdf: (float, float, float) => float = "cdf" } @module("jstat") external sum: array => float = "sum" From 0ac6357ae6add05a316c67f2bfd5c031338b4ef3 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Tue, 12 Apr 2022 20:22:09 -0400 Subject: [PATCH 32/33] `yarn format:all` --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4ae0287b..a0e8fd34 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,8 @@ "private": true, "name": "squiggle", "scripts": { - "nodeclean": "rm -r node_modules && rm -r packages/*/node_modules" + "nodeclean": "rm -r node_modules && rm -r packages/*/node_modules", + "format:all": "prettier --write . && cd packages/squiggle-lang && yarn format" }, "devDependencies": { "prettier": "^2.6.2" From b17f638483550abab777b74df6383d2449caf997 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Tue, 12 Apr 2022 20:48:53 -0400 Subject: [PATCH 33/33] `EBindings` -> `T.EBindings` --- .../rescript/Reducer/Reducer_Expression/Reducer_Expression.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index 8498c294..90e79e8e 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res @@ -104,7 +104,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result bindings->EBindings->Ok + | list{T.EValue(EvCall("$$bindings"))} => bindings->T.EBindings->Ok | list{T.EValue(EvCall("$$bindStatement")), T.EBindings(bindings), statement} => doBindStatement(statement, bindings)