From 417f0060b6ccb0d817d32210a71f765b52a13dd4 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Fri, 22 Apr 2022 15:43:37 +0200 Subject: [PATCH 01/53] inspect and inspect with label (tested) --- .../Reducer/Reducer_debugging_test.res | 12 ++++++++++++ .../Reducer_Dispatch_BuiltIn.res | 17 +++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res new file mode 100644 index 00000000..588dd842 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res @@ -0,0 +1,12 @@ +open Jest +open Reducer_TestHelpers + +/* + You can wrap around any expression with inspect(expr) to log the value of that expression. + This is useful for debugging. inspect(expr) returns the value of expr, but also prints it out. + There is a second version of inspect that takes a label, which will print out the label and the value. +*/ +describe("Debugging", () => { + testEvalToBe("inspect(1)", "Ok(1)") + testEvalToBe("inspect(1, \"one\")", "Ok(1)") +}) 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 21c91dc2..fc14b5d6 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 @@ -43,16 +43,25 @@ let callInternal = (call: functionCall): result<'b, errorValue> => { | None => RERecordPropertyNotFound("Record property not found", sIndex)->Error } + let inspect = (value: expressionValue) => { + Js.log(`${value->toString}`) + value->Ok + } + + let inspectLabel = (value: expressionValue, label: string) => { + Js.log(`${label}: ${value->toString}`) + value->Ok + } + switch call { - // | ("$constructRecord", pairArray) - // | ("$atIndex", [EvArray(anArray), EvNumber(fIndex)]) => arrayAtIndex(anArray, fIndex) - // | ("$atIndex", [EvRecord(aRecord), EvString(sIndex)]) => recordAtIndex(aRecord, sIndex) - | ("$constructRecord", [EvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs) | ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) => arrayAtIndex(aValueArray, fIndex) | ("$atIndex", [EvRecord(dict), EvArray([EvString(sIndex)])]) => recordAtIndex(dict, sIndex) | ("$atIndex", [obj, index]) => (toStringWithType(obj) ++ "??~~~~" ++ toStringWithType(index))->EvString->Ok + | ("$constructRecord", [EvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs) + | ("inspect", [value, EvString(label)]) => inspectLabel(value, label) + | ("inspect", [value]) => inspect(value) | call => callMathJs(call) } } From 9ce5ed53d28c7602ec71b662a47f7bc1b1fbba99 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Fri, 22 Apr 2022 16:18:00 +0200 Subject: [PATCH 02/53] inspectPerformance (tested) --- .../__tests__/Reducer/Reducer_debugging_test.res | 5 +++++ .../Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res index 588dd842..0ce1a90d 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res @@ -4,9 +4,14 @@ open Reducer_TestHelpers /* You can wrap around any expression with inspect(expr) to log the value of that expression. This is useful for debugging. inspect(expr) returns the value of expr, but also prints it out. + There is a second version of inspect that takes a label, which will print out the label and the value. + + inpsectPerformace(expr, label) will print out the value of expr, the label, and the time it took to evaluate expr. */ describe("Debugging", () => { testEvalToBe("inspect(1)", "Ok(1)") testEvalToBe("inspect(1, \"one\")", "Ok(1)") + testEvalToBe("inspect(1, \"one\")", "Ok(1)") + testEvalToBe("inspectPerformance(1, \"one\")", "Ok(1)") }) 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 fc14b5d6..0c1f6c04 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 @@ -53,6 +53,15 @@ let callInternal = (call: functionCall): result<'b, errorValue> => { value->Ok } + let inspectPerformance = (value: expressionValue, label: string) => { + let _ = %raw("{performance} = require('perf_hooks')") + let start = %raw(`performance.now()`) + let finish = %raw(`performance.now()`) + let performance = finish - start + Js.log(`${label}: ${value->toString} performance: ${Js.String.make(performance)}ms`) + value->Ok + } + switch call { | ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) => arrayAtIndex(aValueArray, fIndex) @@ -62,6 +71,7 @@ let callInternal = (call: functionCall): result<'b, errorValue> => { | ("$constructRecord", [EvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs) | ("inspect", [value, EvString(label)]) => inspectLabel(value, label) | ("inspect", [value]) => inspect(value) + | ("inspectPerformance", [value, EvString(label)]) => inspectPerformance(value, label) | call => callMathJs(call) } } From 99906446c5d5a8d1ab7c80e74e09c1f5c758a9d8 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Sat, 23 Apr 2022 15:40:04 +0200 Subject: [PATCH 03/53] resi declaration consistency --- packages/squiggle-lang/src/rescript/Reducer/Reducer.res | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res index d2e4858f..63e1f3a7 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res @@ -5,8 +5,8 @@ module Extra = Reducer_Extra module Js = Reducer_Js module MathJs = Reducer_MathJs -type expressionValue = Reducer_Expression.expressionValue -type externalBindings = Expression.externalBindings +type expressionValue = ReducerInterface_ExpressionValue.expressionValue +type externalBindings = ReducerInterface_ExpressionValue.externalBindings let evaluate = Expression.eval let evaluateUsingExternalBindings = Expression.evalUsingExternalBindings let evaluatePartialUsingExternalBindings = Expression.evalPartialUsingExternalBindings From a915e6804951327258867835e03893980fb4196b Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Sat, 23 Apr 2022 17:55:34 +0200 Subject: [PATCH 04/53] MathJs functionAssingmentNode parsed, comments passed (tested) Just found out that comments were already done --- .../Reducer_MathJsParse_test.res | 19 ++++++++++--------- .../Reducer_MathJs/Reducer_MathJs_Parse.res | 11 +++++++++-- 2 files changed, 19 insertions(+), 11 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 6282c14d..988d5a88 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 @@ -18,6 +18,12 @@ module MySkip = { Skip.test(desc, () => expectParseToBe(expr, answer)) } +module MyOnly = { + let testParse = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer)) + let testDescriptionParse = (desc, expr, answer) => + Only.test(desc, () => expectParseToBe(expr, answer)) +} + describe("MathJs parse", () => { describe("literals operators paranthesis", () => { testParse("1", "1") @@ -40,15 +46,15 @@ describe("MathJs parse", () => { }) describe("functions", () => { - MySkip.testParse("identity(x) = x", "???") - MySkip.testParse("identity(x)", "???") + testParse("identity(x) = x", "identity = (x) => x") + testParse("identity(x)", "identity(x)") }) describe("arrays", () => { 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)") + testParse("range(0, 4)", "range(0, 4)") testDescriptionParse("index", "([0,1,2])[1]", "([0, 1, 2])[1]") }) @@ -58,11 +64,6 @@ describe("MathJs parse", () => { }) describe("comments", () => { - MySkip.testDescriptionParse("define", "# This is a comment", "???") - }) - - describe("if statement", () => { - // TODO Tertiary operator instead - MySkip.testDescriptionParse("define", "if (true) { 1 } else { 0 }", "???") + testDescriptionParse("define", "1 # This is a comment", "1") }) }) 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 e3e2955c..e2acbe55 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 @@ -11,11 +11,10 @@ type block = {"node": node} type blockNode = {...node, "blocks": array} //conditionalNode type constantNode = {...node, "value": unit} -//functionAssignmentNode +type functionAssignmentNode = {...node, "name": string, "params": array, "expr": node} type indexNode = {...node, "dimensions": array} type objectNode = {...node, "properties": Js.Dict.t} type accessorNode = {...node, "object": node, "index": indexNode, "name": string} - type parenthesisNode = {...node, "content": node} //rangeNode //relationalNode @@ -33,6 +32,7 @@ external castAssignmentNodeWAccessor: node => assignmentNodeWAccessor = "%identi external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity" external castBlockNode: node => blockNode = "%identity" external castConstantNode: node => constantNode = "%identity" +external castFunctionAssignmentNode: node => functionAssignmentNode ="%identity" external castFunctionNode: node => functionNode = "%identity" external castIndexNode: node => indexNode = "%identity" external castObjectNode: node => objectNode = "%identity" @@ -59,6 +59,7 @@ type mathJsNode = | MjAssignmentNode(assignmentNode) | MjBlockNode(blockNode) | MjConstantNode(constantNode) + | MjFunctionAssignmentNode(functionAssignmentNode) | MjFunctionNode(functionNode) | MjIndexNode(indexNode) | MjObjectNode(objectNode) @@ -82,6 +83,7 @@ let castNodeType = (node: node) => { | "AssignmentNode" => node->decideAssignmentNode | "BlockNode" => node->castBlockNode->MjBlockNode->Ok | "ConstantNode" => node->castConstantNode->MjConstantNode->Ok + | "FunctionAssignmentNode" => node->castFunctionAssignmentNode->MjFunctionAssignmentNode->Ok | "FunctionNode" => node->castFunctionNode->MjFunctionNode->Ok | "IndexNode" => node->castIndexNode->MjIndexNode->Ok | "ObjectNode" => node->castObjectNode->MjObjectNode->Ok @@ -118,6 +120,10 @@ let rec toString = (mathJsNode: mathJsNode): string => { ->Extra.Array.interperse(", ") ->Js.String.concatMany("") + let toStringFunctionAssignmentNode = (faNode: functionAssignmentNode): string => { + let paramNames = Js.Array2.toString(faNode["params"]) + `${faNode["name"]} = (${paramNames}) => ${toStringMathJsNode(faNode["expr"])}` + } let toStringFunctionNode = (fnode: functionNode): string => `${fnode->nameOfFunctionNode}(${fnode["args"]->toStringNodeArray})` @@ -152,6 +158,7 @@ let rec toString = (mathJsNode: mathJsNode): string => { `${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}` | MjBlockNode(bNode) => `{${bNode["blocks"]->toStringBlocks}}` | MjConstantNode(cNode) => cNode["value"]->toStringValue + | MjFunctionAssignmentNode(faNode) => faNode->toStringFunctionAssignmentNode | MjFunctionNode(fNode) => fNode->toStringFunctionNode | MjIndexNode(iNode) => iNode->toStringIndexNode | MjObjectNode(oNode) => oNode->toStringObjectNode From 88b6d49ad3b910e12738f5db5d8a32a43165e12d Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Sat, 23 Apr 2022 21:13:43 +0200 Subject: [PATCH 05/53] function definition parse (tested) --- .../Reducer/Reducer_functionAssignment_test.res | 12 ++++++++++++ .../Reducer_Dispatch_BuiltInMacros.res | 1 + .../Reducer_Expression/Reducer_Expression.res | 3 +++ .../Reducer_Expression/Reducer_Expression_T.res | 3 ++- .../Reducer_MathJs/Reducer_MathJs_ToExpression.res | 14 ++++++++++++++ 5 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res new file mode 100644 index 00000000..ebc0896f --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res @@ -0,0 +1,12 @@ +open Jest +open Reducer_TestHelpers + +describe("Parse function assignment", () => { + testParseToBe("f(x)=x", "Ok((:$let :f (:$lambda (x) :x)))") + testParseToBe("f(x)=2*x", "Ok((:$let :f (:$lambda (x) (:multiply 2 :x))))") + //MathJs does not allow blocks in function definitions +}) + +Skip.describe("Evaluate function assignment", () => { + testParseToBe("f(x)=x; f(1)", "Ok(1)") +}) \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index d1219f79..7da85124 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -33,6 +33,7 @@ let dispatchMacroCall = ( } | ExpressionT.EValue(_) => expression->Ok | ExpressionT.EBindings(_) => expression->Ok + | ExpressionT.EParameters(_) => expression->Ok | ExpressionT.EList(list) => { let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => racc->Result.flatMap(acc => { 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 68881496..30f8d96c 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 @@ -16,6 +16,7 @@ type t = expression let rec toString = expression => switch expression { | T.EBindings(_) => "$$bound" + | T.EParameters(params) => `(${Js.Array2.toString(params->Belt.List.toArray)})` | T.EList(aList) => `(${Belt.List.map(aList, aValue => toString(aValue)) ->Extra.List.interperse(" ") @@ -72,6 +73,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result expression->Ok | T.EBindings(_value) => expression->Ok + | T.EParameters(_value) => expression->Ok | T.EList(list) => { let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( racc, @@ -108,6 +110,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): resultResult.flatMap(acc => acc->reduceValueList) } | EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error + | EParameters(_parameters) => RETodo("Error: Lambda Parameters cannot be reduced to values")->Error } let rExpandedExpression: result = expression->seekMacros(bindings) 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 fe938316..5f141195 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 @@ -11,5 +11,6 @@ open ReducerInterface.ExpressionValue 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 + | EBindings(bindings) // $let kind of statements return bindings; for internal use only + | EParameters(list) // for $defun; for internal use only and bindings = Belt.Map.String.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 a8b7b39a..2d0bcdd6 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 @@ -99,6 +99,19 @@ let rec fromNode = (mathJsNode: Parse.node): result => }) } + let caseFunctionAssignmentNode = faNode => { + let symbol = faNode["name"]->toEvSymbolValue + let rValueExpression = fromNode(faNode["expr"]) + + rValueExpression->Result.flatMap(valueExpression => { + let lispParams = faNode["params"]->Belt.List.fromArray->ExpressionT.EParameters + let rLambda = passToFunction("$lambda", list{lispParams, valueExpression}->Ok) + rLambda -> Result.flatMap( lambda => { + passToFunction("$let", list{symbol, lambda}->Ok) + }) + }) + } + let caseArrayNode = aNode => { aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list)) } @@ -115,6 +128,7 @@ let rec fromNode = (mathJsNode: Parse.node): result => | MjBlockNode(bNode) => bNode["blocks"]->Belt.Array.map(toTagOrNode)->caseTagOrNodes | MjConstantNode(cNode) => cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok) + | MjFunctionAssignmentNode(faNode) => caseFunctionAssignmentNode(faNode) | MjFunctionNode(fNode) => fNode->caseFunctionNode | MjIndexNode(iNode) => caseIndexNode(iNode) | MjObjectNode(oNode) => caseObjectNode(oNode) From fe4e355fbef8412b3db2c5bfad4cc2da228d7159 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Sun, 24 Apr 2022 18:42:54 +0200 Subject: [PATCH 06/53] format --- .../__tests__/Reducer/Reducer_TestHelpers.res | 5 ++++- .../__tests__/Reducer/Reducer_debugging_test.res | 8 ++++---- .../Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res | 2 +- .../Reducer/Reducer_MathJs/Reducer_MathJs_Parse.res | 6 +++--- .../Reducer_MathJs/Reducer_MathJs_ToExpression.res | 4 ++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res index 0790c078..581f6c8a 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res @@ -17,7 +17,10 @@ let expectEvalToBe = (expr: string, answer: string) => Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer) let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) => - Reducer.evaluateUsingExternalBindings(expr, bindings)->ExpressionValue.toStringResult->expect->toBe(answer) + Reducer.evaluateUsingExternalBindings(expr, bindings) + ->ExpressionValue.toStringResult + ->expect + ->toBe(answer) let expectEvalPartialBindingsToBe = ( expr: string, diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res index 0ce1a90d..3a2eea97 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res @@ -10,8 +10,8 @@ open Reducer_TestHelpers inpsectPerformace(expr, label) will print out the value of expr, the label, and the time it took to evaluate expr. */ describe("Debugging", () => { - testEvalToBe("inspect(1)", "Ok(1)") - testEvalToBe("inspect(1, \"one\")", "Ok(1)") - testEvalToBe("inspect(1, \"one\")", "Ok(1)") - testEvalToBe("inspectPerformance(1, \"one\")", "Ok(1)") + testEvalToBe("inspect(1)", "Ok(1)") + testEvalToBe("inspect(1, \"one\")", "Ok(1)") + testEvalToBe("inspect(1, \"one\")", "Ok(1)") + testEvalToBe("inspectPerformance(1, \"one\")", "Ok(1)") }) 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 0c1f6c04..e107016f 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 @@ -44,7 +44,7 @@ let callInternal = (call: functionCall): result<'b, errorValue> => { } let inspect = (value: expressionValue) => { - Js.log(`${value->toString}`) + Js.log(value->toString) value->Ok } 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 e2acbe55..1f5df97d 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 @@ -32,7 +32,7 @@ external castAssignmentNodeWAccessor: node => assignmentNodeWAccessor = "%identi external castAssignmentNodeWIndex: node => assignmentNodeWIndex = "%identity" external castBlockNode: node => blockNode = "%identity" external castConstantNode: node => constantNode = "%identity" -external castFunctionAssignmentNode: node => functionAssignmentNode ="%identity" +external castFunctionAssignmentNode: node => functionAssignmentNode = "%identity" external castFunctionNode: node => functionNode = "%identity" external castIndexNode: node => indexNode = "%identity" external castObjectNode: node => objectNode = "%identity" @@ -123,7 +123,7 @@ let rec toString = (mathJsNode: mathJsNode): string => { let toStringFunctionAssignmentNode = (faNode: functionAssignmentNode): string => { let paramNames = Js.Array2.toString(faNode["params"]) `${faNode["name"]} = (${paramNames}) => ${toStringMathJsNode(faNode["expr"])}` - } + } let toStringFunctionNode = (fnode: functionNode): string => `${fnode->nameOfFunctionNode}(${fnode["args"]->toStringNodeArray})` @@ -158,7 +158,7 @@ let rec toString = (mathJsNode: mathJsNode): string => { `${aNode["object"]->toStringSymbolNode} = ${aNode["value"]->toStringMathJsNode}` | MjBlockNode(bNode) => `{${bNode["blocks"]->toStringBlocks}}` | MjConstantNode(cNode) => cNode["value"]->toStringValue - | MjFunctionAssignmentNode(faNode) => faNode->toStringFunctionAssignmentNode + | MjFunctionAssignmentNode(faNode) => faNode->toStringFunctionAssignmentNode | MjFunctionNode(fNode) => fNode->toStringFunctionNode | MjIndexNode(iNode) => iNode->toStringIndexNode | MjObjectNode(oNode) => oNode->toStringObjectNode 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 2d0bcdd6..45184a89 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 @@ -106,12 +106,12 @@ let rec fromNode = (mathJsNode: Parse.node): result => rValueExpression->Result.flatMap(valueExpression => { let lispParams = faNode["params"]->Belt.List.fromArray->ExpressionT.EParameters let rLambda = passToFunction("$lambda", list{lispParams, valueExpression}->Ok) - rLambda -> Result.flatMap( lambda => { + rLambda->Result.flatMap(lambda => { passToFunction("$let", list{symbol, lambda}->Ok) }) }) } - + let caseArrayNode = aNode => { aNode["items"]->Belt.List.fromArray->fromNodeList->Result.map(list => ExpressionT.EList(list)) } From 5d88fae40c80fca73b65f56eaa6dd241c3b88cb5 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 01:09:51 +0200 Subject: [PATCH 07/53] internalCode --- .../ReducerInterface/ReducerInterface_ExpressionValue.res | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 2cbd1ead..f81bcbe4 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -5,12 +5,16 @@ module Extra_Array = Reducer_Extra_Array module ErrorValue = Reducer_ErrorValue +@genType.opaque +type internalCode = Object + @genType type rec expressionValue = | EvArray(array) | EvBool(bool) | EvCall(string) // External function call | EvDistribution(GenericDist_Types.genericDist) + | EvLambda(array, internalCode) | EvNumber(float) | EvRecord(Js.Dict.t) | EvString(string) @@ -25,6 +29,7 @@ let rec toString = aValue => switch aValue { | EvBool(aBool) => Js.String.make(aBool) | EvCall(fName) => `:${fName}` + | EvLambda(parameters, _internalCode) => `lambda(${Js.Array2.toString(parameters)}=>internal)` | EvNumber(aNumber) => Js.String.make(aNumber) | EvString(aString) => `'${aString}'` | EvSymbol(aString) => `:${aString}` From 1f989de11c4fcfd87cbec1a96339ce870b4efb1c Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 01:53:37 +0200 Subject: [PATCH 08/53] lambda binding --- .../Reducer_Dispatch_BuiltInMacros.res | 88 +++++++++++++------ .../Reducer_Expression/Reducer_Expression.res | 3 + 2 files changed, 65 insertions(+), 26 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index 7da85124..a17036de 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -16,37 +16,73 @@ type reducerFn = ( ExpressionT.bindings, ) => result +let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings): result< + expression, + errorValue, +> => { + let getParameters = (bindings: ExpressionT.bindings): list => { + let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters(list{})) + switch eParameters { + | EParameters(parameters) => parameters + | _ => list{} + } + } + + let putParameters = ( + bindings: ExpressionT.bindings, + parameters: list, + ): ExpressionT.bindings => + Belt.Map.String.set(bindings, "$parameters", ExpressionT.EParameters(parameters)) + switch expression { + | ExpressionT.EValue(EvSymbol(aSymbol)) => { + let parameters = getParameters(bindings) + switch Belt.List.has(parameters, aSymbol, (a, b) => a == b) { + | true => expression->Ok // We cannot bind the parameters with global values + | false => + switch bindings->Belt.Map.String.get(aSymbol) { + | Some(boundExpression) => boundExpression->Ok + | None => RESymbolNotFound(aSymbol)->Error + } + } + } + | ExpressionT.EValue(_) => expression->Ok + | ExpressionT.EBindings(_) => expression->Ok + | ExpressionT.EParameters(_) => expression->Ok + | ExpressionT.EList(list{ + ExpressionT.EValue(EvCall("$lambda")), + ExpressionT.EParameters(parameters), + expr, + }) => { + let oldParameters = getParameters(bindings) + let newParameters = oldParameters->Belt.List.concat(parameters) + let newBindings = putParameters(bindings, newParameters) + let rNewExpr = replaceSymbols(expr, newBindings) + rNewExpr -> Result.flatMap(newExpr => ExpressionT.EList(list{ + ExpressionT.EValue(EvCall("$lambda")), + ExpressionT.EParameters(parameters), + newExpr + })->Ok) + } + | ExpressionT.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 + }) + }) + ) + racc->Result.map(acc => acc->ExpressionT.EList) + } + } +} + let dispatchMacroCall = ( list: list, bindings: ExpressionT.bindings, reduceExpression: reducerFn, ): result => { - let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings): result< - expression, - errorValue, - > => - switch expression { - | ExpressionT.EValue(EvSymbol(aSymbol)) => - switch bindings->Belt.Map.String.get(aSymbol) { - | Some(boundExpression) => boundExpression->Ok - | None => RESymbolNotFound(aSymbol)->Error - } - | ExpressionT.EValue(_) => expression->Ok - | ExpressionT.EBindings(_) => expression->Ok - | ExpressionT.EParameters(_) => expression->Ok - | ExpressionT.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 - }) - }) - ) - racc->Result.map(acc => acc->ExpressionT.EList) - } - } let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => { switch statement { 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 30f8d96c..1153491b 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 @@ -93,6 +93,9 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result => switch expression { + // | T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) => { + // let lambda = T.ELambda(parameters, functionDefinition) + // lambda->Ok} | T.EValue(value) => value->Ok | T.EList(list) => { let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( From e3ef08839f4d3749a6801cf1874e30068b3bf95e Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 02:37:35 +0200 Subject: [PATCH 09/53] Function definition evaluated --- .../Reducer_functionAssignment_test.res | 6 ++-- .../Reducer_Dispatch_BuiltInMacros.res | 34 ++++++++++--------- .../Reducer_Expression/Reducer_Expression.res | 21 ++++++++---- .../Reducer_Expression_T.res | 2 +- .../Reducer_MathJs_ToExpression.res | 2 +- .../ReducerInterface_ExpressionValue.res | 7 ++-- 6 files changed, 42 insertions(+), 30 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res index ebc0896f..9259dacd 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res @@ -7,6 +7,6 @@ describe("Parse function assignment", () => { //MathJs does not allow blocks in function definitions }) -Skip.describe("Evaluate function assignment", () => { - testParseToBe("f(x)=x; f(1)", "Ok(1)") -}) \ No newline at end of file +describe("Evaluate function assignment", () => { + testEvalToBe("f(x)=x; f(1)", "Ok(1)") +}) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index a17036de..0785d2a9 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -20,28 +20,29 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings expression, errorValue, > => { - let getParameters = (bindings: ExpressionT.bindings): list => { - let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters(list{})) + let getParameters = (bindings: ExpressionT.bindings): array => { + let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters([])) switch eParameters { | EParameters(parameters) => parameters - | _ => list{} + | _ => [] } } let putParameters = ( bindings: ExpressionT.bindings, - parameters: list, + parameters: array, ): ExpressionT.bindings => Belt.Map.String.set(bindings, "$parameters", ExpressionT.EParameters(parameters)) + switch expression { | ExpressionT.EValue(EvSymbol(aSymbol)) => { let parameters = getParameters(bindings) - switch Belt.List.has(parameters, aSymbol, (a, b) => a == b) { + switch Js.Array2.some(parameters, a => a == aSymbol) { | true => expression->Ok // We cannot bind the parameters with global values | false => - switch bindings->Belt.Map.String.get(aSymbol) { - | Some(boundExpression) => boundExpression->Ok - | None => RESymbolNotFound(aSymbol)->Error + switch bindings->Belt.Map.String.get(aSymbol) { + | Some(boundExpression) => boundExpression->Ok + | None => RESymbolNotFound(aSymbol)->Error } } } @@ -54,14 +55,16 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings expr, }) => { let oldParameters = getParameters(bindings) - let newParameters = oldParameters->Belt.List.concat(parameters) + let newParameters = oldParameters->Js.Array2.concat(parameters) let newBindings = putParameters(bindings, newParameters) let rNewExpr = replaceSymbols(expr, newBindings) - rNewExpr -> Result.flatMap(newExpr => ExpressionT.EList(list{ - ExpressionT.EValue(EvCall("$lambda")), - ExpressionT.EParameters(parameters), - newExpr - })->Ok) + rNewExpr->Result.flatMap(newExpr => + ExpressionT.EList(list{ + ExpressionT.EValue(EvCall("$lambda")), + ExpressionT.EParameters(parameters), + newExpr, + })->Ok + ) } | ExpressionT.EList(list) => { let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => @@ -77,13 +80,12 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings } } } - + let dispatchMacroCall = ( list: list, bindings: ExpressionT.bindings, reduceExpression: reducerFn, ): result => { - let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => { switch statement { | ExpressionT.EList(list{ 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 1153491b..7923db48 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 @@ -8,15 +8,19 @@ open Reducer_ErrorValue type expression = T.expression type expressionValue = ExpressionValue.expressionValue +type internalCode = ExpressionValue.internalCode type t = expression +external castExpressionToInternalCode: expression => internalCode = "%identity" +external castInternalCodeToInternalCode: internalCode => expression = "%identity" + /* Shows the expression as text of expression */ let rec toString = expression => switch expression { | T.EBindings(_) => "$$bound" - | T.EParameters(params) => `(${Js.Array2.toString(params->Belt.List.toArray)})` + | T.EParameters(params) => `(${Js.Array2.toString(params)})` | T.EList(aList) => `(${Belt.List.map(aList, aValue => toString(aValue)) ->Extra.List.interperse(" ") @@ -93,9 +97,11 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result => switch expression { - // | T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) => { - // let lambda = T.ELambda(parameters, functionDefinition) - // lambda->Ok} + | T.EList(list{ + T.EValue(EvCall("$lambda")), + T.EParameters(parameters), + functionDefinition, + }) => EvLambda(parameters, functionDefinition->castExpressionToInternalCode)->Ok | T.EValue(value) => value->Ok | T.EList(list) => { let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( @@ -113,7 +119,8 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): resultResult.flatMap(acc => acc->reduceValueList) } | EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error - | EParameters(_parameters) => RETodo("Error: Lambda Parameters cannot be reduced to values")->Error + | EParameters(_parameters) => + RETodo("Error: Lambda Parameters cannot be reduced to values")->Error } let rExpandedExpression: result = expression->seekMacros(bindings) @@ -142,7 +149,9 @@ let evalPartialUsingExternalBindings_ = (codeText: string, bindings: T.bindings) Therefore all statments are assignments. */ let evalOuterWBindings_ = (codeText: string, bindings: T.bindings) => { - parseOuter(codeText)->Result.flatMap(expression => expression->evalUsingExternalBindingsExpression_(bindings)) + parseOuter(codeText)->Result.flatMap(expression => + expression->evalUsingExternalBindingsExpression_(bindings) + ) } /* 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 5f141195..c3fd822c 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 @@ -12,5 +12,5 @@ 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 kind of statements return bindings; for internal use only - | EParameters(list) // for $defun; for internal use only + | EParameters(array) // for $defun; for internal use only and bindings = Belt.Map.String.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 45184a89..bf1fcafc 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 @@ -104,7 +104,7 @@ let rec fromNode = (mathJsNode: Parse.node): result => let rValueExpression = fromNode(faNode["expr"]) rValueExpression->Result.flatMap(valueExpression => { - let lispParams = faNode["params"]->Belt.List.fromArray->ExpressionT.EParameters + let lispParams = faNode["params"]->ExpressionT.EParameters let rLambda = passToFunction("$lambda", list{lispParams, valueExpression}->Ok) rLambda->Result.flatMap(lambda => { passToFunction("$let", list{symbol, lambda}->Ok) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index f81bcbe4..1536be74 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -56,14 +56,15 @@ and toStringRecord = aRecord => { let toStringWithType = aValue => switch aValue { + | EvArray(_) => `Array::${toString(aValue)}` | EvBool(_) => `Bool::${toString(aValue)}` | EvCall(_) => `Call::${toString(aValue)}` + | EvDistribution(_) => `Distribution::${toString(aValue)}` + | EvLambda(_parameters, _internalCode) => `Lambda::${toString(aValue)}` | EvNumber(_) => `Number::${toString(aValue)}` + | EvRecord(_) => `Record::${toString(aValue)}` | EvString(_) => `String::${toString(aValue)}` | EvSymbol(_) => `Symbol::${toString(aValue)}` - | EvArray(_) => `Array::${toString(aValue)}` - | EvRecord(_) => `Record::${toString(aValue)}` - | EvDistribution(_) => `Distribution::${toString(aValue)}` } let argsToString = (args: array): string => { From 7b080ff4c2ce9da98d8000f27c9998ef5eadeece Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 03:01:58 +0200 Subject: [PATCH 10/53] bind function calls --- .../Reducer_Dispatch_BuiltInMacros.res | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index 0785d2a9..a9432757 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -34,17 +34,24 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings ): ExpressionT.bindings => Belt.Map.String.set(bindings, "$parameters", ExpressionT.EParameters(parameters)) - switch expression { - | ExpressionT.EValue(EvSymbol(aSymbol)) => { - let parameters = getParameters(bindings) - switch Js.Array2.some(parameters, a => a == aSymbol) { - | true => expression->Ok // We cannot bind the parameters with global values + let answerBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) => + switch Js.Array2.some(parameters, a => a == aSymbol) { + | true => defaultExpression->Ok // We cannot bind the parameters with global values | false => switch bindings->Belt.Map.String.get(aSymbol) { | Some(boundExpression) => boundExpression->Ok | None => RESymbolNotFound(aSymbol)->Error } } + + switch expression { + | ExpressionT.EValue(EvSymbol(aSymbol)) => { + let parameters = getParameters(bindings) + answerBindingIfNotParameter(aSymbol, expression, parameters, bindings) + } + | ExpressionT.EValue(EvCall(aSymbol)) => { + let parameters = getParameters(bindings) + answerBindingIfNotParameter(aSymbol, expression, parameters, bindings) } | ExpressionT.EValue(_) => expression->Ok | ExpressionT.EBindings(_) => expression->Ok From d214bddc82fccd01b3e991bf8588f4474e117215 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 06:30:25 +0200 Subject: [PATCH 11/53] lambda expressions bound to function call symbols --- .../Reducer_Dispatch_BuiltInMacros.res | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index a9432757..b32c430d 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -44,6 +44,16 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings } } + let answerCallBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) => + switch Js.Array2.some(parameters, a => a == aSymbol) { + | true => defaultExpression->Ok // We cannot bind the parameters with global values + | false => + switch bindings->Belt.Map.String.get(aSymbol) { + | Some(boundExpression) => boundExpression->Ok + | None => defaultExpression->Ok + } + } + switch expression { | ExpressionT.EValue(EvSymbol(aSymbol)) => { let parameters = getParameters(bindings) @@ -51,7 +61,7 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings } | ExpressionT.EValue(EvCall(aSymbol)) => { let parameters = getParameters(bindings) - answerBindingIfNotParameter(aSymbol, expression, parameters, bindings) + answerCallBindingIfNotParameter(aSymbol, expression, parameters, bindings) } | ExpressionT.EValue(_) => expression->Ok | ExpressionT.EBindings(_) => expression->Ok From 1fb9218a94bbbccccb0ee00f4b35cd7b61125aa2 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 08:17:44 +0200 Subject: [PATCH 12/53] refactor passToFunction --- .../Reducer_Dispatch_BuiltInMacros.res | 28 +++++----- .../Reducer_Expression/Reducer_Expression.res | 33 +++++++++-- .../Reducer_Expression_Builder.res | 16 ++++++ .../Reducer_MathJs_ToExpression.res | 55 ++++++++----------- 4 files changed, 80 insertions(+), 52 deletions(-) create mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index b32c430d..a8775590 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -34,25 +34,25 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings ): ExpressionT.bindings => Belt.Map.String.set(bindings, "$parameters", ExpressionT.EParameters(parameters)) - let answerBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) => + let answerBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) => switch Js.Array2.some(parameters, a => a == aSymbol) { - | true => defaultExpression->Ok // We cannot bind the parameters with global values - | false => - switch bindings->Belt.Map.String.get(aSymbol) { - | Some(boundExpression) => boundExpression->Ok - | None => RESymbolNotFound(aSymbol)->Error - } + | true => defaultExpression->Ok // We cannot bind the parameters with global values + | false => + switch bindings->Belt.Map.String.get(aSymbol) { + | Some(boundExpression) => boundExpression->Ok + | None => RESymbolNotFound(aSymbol)->Error } + } - let answerCallBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) => + let answerCallBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) => switch Js.Array2.some(parameters, a => a == aSymbol) { - | true => defaultExpression->Ok // We cannot bind the parameters with global values - | false => - switch bindings->Belt.Map.String.get(aSymbol) { - | Some(boundExpression) => boundExpression->Ok - | None => defaultExpression->Ok - } + | true => defaultExpression->Ok // We cannot bind the parameters with global values + | false => + switch bindings->Belt.Map.String.get(aSymbol) { + | Some(boundExpression) => boundExpression->Ok + | None => defaultExpression->Ok } + } switch expression { | ExpressionT.EValue(EvSymbol(aSymbol)) => { 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 7923db48..3e670a17 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 @@ -12,7 +12,7 @@ type internalCode = ExpressionValue.internalCode type t = expression external castExpressionToInternalCode: expression => internalCode = "%identity" -external castInternalCodeToInternalCode: internalCode => expression = "%identity" +external castInternalCodeToExpression: internalCode => expression = "%identity" /* Shows the expression as text of expression @@ -64,12 +64,36 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result, bindings: T.bindings): result => Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, reduceExpression) + let applyParametersToLambda = ( + internal: internalCode, + parameters: array, + args: list, + ): result => { + let expr = castInternalCodeToExpression(internal) + let parameterList = parameters->Belt.List.fromArray + let zippedParameterList = parameterList->Belt.List.zip(args) + let bindings = Belt.List.reduce(zippedParameterList, defaultBindings, (a, (p, e)) => + a->Belt.Map.String.set(p, e->EValue) + ) + Js.log(`applyParametersToLambda: ${toString(expr)}`) + let inspectBindings = + bindings + ->Belt.Map.String.mapWithKey((k, v) => `${k}: ${toString(v)}`) + ->Belt.Map.String.valuesToArray + ->Js.Array2.toString + Js.log(` inspectBindings: ${inspectBindings}`) + reduceExpression(expr, bindings) + } + /* 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 + // "(lambda(x=>internal) param)" + | list{EvLambda(parameters, internal), ...args} => + applyParametersToLambda(internal, parameters, args) | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok } @@ -97,11 +121,8 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result => switch expression { - | T.EList(list{ - T.EValue(EvCall("$lambda")), - T.EParameters(parameters), - functionDefinition, - }) => EvLambda(parameters, functionDefinition->castExpressionToInternalCode)->Ok + | T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) => + EvLambda(parameters, functionDefinition->castExpressionToInternalCode)->Ok | T.EValue(value) => value->Ok | T.EList(list) => { let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res new file mode 100644 index 00000000..4e5a988e --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res @@ -0,0 +1,16 @@ +module ErrorValue = Reducer_ErrorValue +module ExpressionT = Reducer_Expression_T +module ExpressionValue = ReducerInterface.ExpressionValue +module Result = Belt.Result + +type errorValue = ErrorValue.errorValue +type expression = ExpressionT.expression + +let passToFunction = (fName: string, lispArgs: list): expression => { + let toEvCallValue = (name: string): expression => name->ExpressionValue.EvCall->ExpressionT.EValue + let fn = fName->toEvCallValue + list{fn, ...lispArgs}->ExpressionT.EList +} + +let toEvSymbolValue = (name: string): expression => + name->ExpressionValue.EvSymbol->ExpressionT.EValue 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 bf1fcafc..5dc53413 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,6 +1,7 @@ +module Builder = Reducer_Expression_Builder module ErrorValue = Reducer_ErrorValue -module ExpressionValue = ReducerInterface.ExpressionValue module ExpressionT = Reducer_Expression_T +module ExpressionValue = ReducerInterface.ExpressionValue module JavaScript = Reducer_Js module Parse = Reducer_MathJs_Parse module Result = Belt.Result @@ -9,13 +10,6 @@ type expression = ExpressionT.expression type expressionValue = ExpressionValue.expressionValue type errorValue = ErrorValue.errorValue -let passToFunction = (fName: string, rLispArgs): result => { - let toEvCallValue = (name: string): expression => name->ExpressionValue.EvCall->ExpressionT.EValue - - let fn = fName->toEvCallValue - rLispArgs->Result.flatMap(lispArgs => list{fn, ...lispArgs}->ExpressionT.EList->Ok) -} - type blockTag = | ImportVariablesStatement | ExportVariablesExpression @@ -34,12 +28,11 @@ let rec fromNode = (mathJsNode: Parse.node): result => ) ) - let toEvSymbolValue = (name: string): expression => - name->ExpressionValue.EvSymbol->ExpressionT.EValue - let caseFunctionNode = fNode => { - let lispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList - passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs) + let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList + rLispArgs->Result.flatMap(lispArgs => + Builder.passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs)->Ok + ) } let caseObjectNode = oNode => { @@ -60,8 +53,8 @@ let rec fromNode = (mathJsNode: Parse.node): result => ) ) rargs->Result.flatMap(args => - passToFunction("$constructRecord", list{ExpressionT.EList(args)}->Ok) - ) // $consturctRecord gets a single argument: List of key-value paiers + Builder.passToFunction("$constructRecord", list{ExpressionT.EList(args)})->Ok + ) // $constructRecord gets a single argument: List of key-value paiers } oNode["properties"]->Js.Dict.entries->Belt.List.fromArray->fromObjectEntries @@ -85,30 +78,27 @@ let rec fromNode = (mathJsNode: Parse.node): result => let caseAccessorNode = (objectNode, indexNode) => { caseIndexNode(indexNode)->Result.flatMap(indexCode => { fromNode(objectNode)->Result.flatMap(objectCode => - passToFunction("$atIndex", list{objectCode, indexCode}->Ok) + Builder.passToFunction("$atIndex", list{objectCode, indexCode})->Ok ) }) } let caseAssignmentNode = aNode => { - let symbol = aNode["object"]["name"]->toEvSymbolValue + let symbol = aNode["object"]["name"]->Builder.toEvSymbolValue let rValueExpression = fromNode(aNode["value"]) - rValueExpression->Result.flatMap(valueExpression => { - let lispArgs = list{symbol, valueExpression}->Ok - passToFunction("$let", lispArgs) - }) + rValueExpression->Result.flatMap(valueExpression => + Builder.passToFunction("$let", list{symbol, valueExpression})->Ok + ) } let caseFunctionAssignmentNode = faNode => { - let symbol = faNode["name"]->toEvSymbolValue + let symbol = faNode["name"]->Builder.toEvSymbolValue let rValueExpression = fromNode(faNode["expr"]) rValueExpression->Result.flatMap(valueExpression => { let lispParams = faNode["params"]->ExpressionT.EParameters - let rLambda = passToFunction("$lambda", list{lispParams, valueExpression}->Ok) - rLambda->Result.flatMap(lambda => { - passToFunction("$let", list{symbol, lambda}->Ok) - }) + let lambda = Builder.passToFunction("$lambda", list{lispParams, valueExpression}) + Builder.passToFunction("$let", list{symbol, lambda})->Ok }) } @@ -121,7 +111,7 @@ let rec fromNode = (mathJsNode: Parse.node): result => | MjArrayNode(aNode) => caseArrayNode(aNode) | MjAssignmentNode(aNode) => caseAssignmentNode(aNode) | MjSymbolNode(sNode) => { - let expr: expression = toEvSymbolValue(sNode["name"]) + let expr: expression = Builder.toEvSymbolValue(sNode["name"]) let rExpr: result = expr->Ok rExpr } @@ -138,7 +128,7 @@ let rec fromNode = (mathJsNode: Parse.node): result => rFinalExpression }) and caseTagOrNodes = (tagOrNodes): result => { - let initialBindings = passToFunction("$$bindings", list{}->Ok) + let initialBindings = Builder.passToFunction("$$bindings", list{})->Ok let lastIndex = Belt.Array.length(tagOrNodes) - 1 tagOrNodes->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, tagOrNode, i) => { rPreviousBindings->Result.flatMap(previousBindings => { @@ -146,8 +136,10 @@ and caseTagOrNodes = (tagOrNodes): result => { | BlockNode(node) => fromNode(node) | BlockTag(tag) => switch tag { - | ImportVariablesStatement => passToFunction("$importVariablesStatement", list{}->Ok) - | ExportVariablesExpression => passToFunction("$exportVariablesExpression", list{}->Ok) + | ImportVariablesStatement => + Builder.passToFunction("$importVariablesStatement", list{})->Ok + | ExportVariablesExpression => + Builder.passToFunction("$exportVariablesExpression", list{})->Ok } } @@ -158,8 +150,7 @@ and caseTagOrNodes = (tagOrNodes): result => { } rStatement->Result.flatMap((statement: expression) => { - let lispArgs = list{previousBindings, statement}->Ok - passToFunction(bindName, lispArgs) + Builder.passToFunction(bindName, list{previousBindings, statement})->Ok }) }) }) From eba087329fd5d9128a69d09a703e31ae123ee704 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 08:33:48 +0200 Subject: [PATCH 13/53] called lamda with arguments (tested) --- .../Reducer_Expression/Reducer_Expression.res | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 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 3e670a17..6243b380 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 @@ -1,9 +1,11 @@ +module Builder = Reducer_Expression_Builder module BuiltIn = Reducer_Dispatch_BuiltIn module ExpressionValue = ReducerInterface.ExpressionValue module Extra = Reducer_Extra module MathJs = Reducer_MathJs module Result = Belt.Result module T = Reducer_Expression_T + open Reducer_ErrorValue type expression = T.expression @@ -75,14 +77,11 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result a->Belt.Map.String.set(p, e->EValue) ) - Js.log(`applyParametersToLambda: ${toString(expr)}`) - let inspectBindings = - bindings - ->Belt.Map.String.mapWithKey((k, v) => `${k}: ${toString(v)}`) - ->Belt.Map.String.valuesToArray - ->Js.Array2.toString - Js.log(` inspectBindings: ${inspectBindings}`) - reduceExpression(expr, bindings) + let newExpression = Builder.passToFunction( + "$$bindExpression", + list{Builder.passToFunction("$$bindings", list{}), expr}, + ) + reduceExpression(newExpression, bindings) } /* From c5e08cfdb6f385f95055abc17655877ed6adbd44 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 09:17:38 +0200 Subject: [PATCH 14/53] modify lambda --- .../Reducer/Reducer_Expression/Reducer_Expression.res | 4 ++-- .../ReducerInterface/ReducerInterface_ExpressionValue.res | 6 +++--- 2 files changed, 5 insertions(+), 5 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 6243b380..0fdb890d 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 @@ -91,7 +91,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result (fName, args->Belt.List.toArray)->BuiltIn.dispatch // "(lambda(x=>internal) param)" - | list{EvLambda(parameters, internal), ...args} => + | list{EvLambda((parameters, internal)), ...args} => applyParametersToLambda(internal, parameters, args) | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok } @@ -121,7 +121,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result => switch expression { | T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) => - EvLambda(parameters, functionDefinition->castExpressionToInternalCode)->Ok + EvLambda((parameters, functionDefinition->castExpressionToInternalCode))->Ok | T.EValue(value) => value->Ok | T.EList(list) => { let racc: result, 'e> = list->Belt.List.reduceReverse(Ok(list{}), ( diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 1536be74..2b11a62f 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -14,7 +14,7 @@ type rec expressionValue = | EvBool(bool) | EvCall(string) // External function call | EvDistribution(GenericDist_Types.genericDist) - | EvLambda(array, internalCode) + | EvLambda((array, internalCode)) | EvNumber(float) | EvRecord(Js.Dict.t) | EvString(string) @@ -29,7 +29,7 @@ let rec toString = aValue => switch aValue { | EvBool(aBool) => Js.String.make(aBool) | EvCall(fName) => `:${fName}` - | EvLambda(parameters, _internalCode) => `lambda(${Js.Array2.toString(parameters)}=>internal)` + | EvLambda((parameters, _internalCode)) => `lambda(${Js.Array2.toString(parameters)}=>internal)` | EvNumber(aNumber) => Js.String.make(aNumber) | EvString(aString) => `'${aString}'` | EvSymbol(aString) => `:${aString}` @@ -60,7 +60,7 @@ let toStringWithType = aValue => | EvBool(_) => `Bool::${toString(aValue)}` | EvCall(_) => `Call::${toString(aValue)}` | EvDistribution(_) => `Distribution::${toString(aValue)}` - | EvLambda(_parameters, _internalCode) => `Lambda::${toString(aValue)}` + | EvLambda((_parameters, _internalCode)) => `Lambda::${toString(aValue)}` | EvNumber(_) => `Number::${toString(aValue)}` | EvRecord(_) => `Record::${toString(aValue)}` | EvString(_) => `String::${toString(aValue)}` From 6a87e8db28b486fc58eef26f1eded516d737626a Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 09:20:27 +0200 Subject: [PATCH 15/53] index.ts FAILURE!!!! --- packages/squiggle-lang/src/js/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 6ff022e0..c8731b0f 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -81,10 +81,13 @@ function tag(x: a, y: b): tagged { return { tag: x, value: y }; } +export abstract class internalCode { protected opaque!: any }; /* simulate opaque types */ + export type squiggleExpression = | tagged<"symbol", string> | tagged<"string", string> | tagged<"call", string> + | tagged<"lambda", [string[], internalCode]> | tagged<"array", squiggleExpression[]> | tagged<"boolean", boolean> | tagged<"distribution", Distribution> @@ -115,6 +118,8 @@ function createTsExport( return tag("boolean", x.value); case "EvCall": return tag("call", x.value); + case "EvLambda": + return tag("lambda", x.value); case "EvDistribution": return tag("distribution", new Distribution(x.value, sampEnv)); case "EvNumber": From c7be29346626797b6ea645e62c8db9d9a2c2573a Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 09:57:02 +0200 Subject: [PATCH 16/53] remove duplicate debug test case --- .../squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res index 3a2eea97..4baee94d 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res @@ -12,6 +12,5 @@ open Reducer_TestHelpers describe("Debugging", () => { testEvalToBe("inspect(1)", "Ok(1)") testEvalToBe("inspect(1, \"one\")", "Ok(1)") - testEvalToBe("inspect(1, \"one\")", "Ok(1)") testEvalToBe("inspectPerformance(1, \"one\")", "Ok(1)") }) From 3788cb0c9a8de21f52590b4bef65c8a86eb02e2f Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 10:52:13 +0200 Subject: [PATCH 17/53] fix variant warnings --- .../Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res | 4 ++-- .../Reducer/Reducer_Expression/Reducer_Expression.res | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index a8775590..5facc9e7 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -140,13 +140,13 @@ let dispatchMacroCall = ( expressionValue, ) => { let value = switch expressionValue { - | EValue(aValue) => aValue + | ExpressionT.EValue(aValue) => aValue | _ => EvSymbol("internal") } Js.Dict.set(acc, key, value) acc }) - externalBindings->EvRecord->ExpressionT.EValue->Ok + externalBindings->ExpressionValue.EvRecord->ExpressionT.EValue->Ok } let doBindExpression = (expression: expression, bindings: ExpressionT.bindings) => 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 0fdb890d..d27ece78 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 @@ -75,7 +75,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): resultBelt.List.fromArray let zippedParameterList = parameterList->Belt.List.zip(args) let bindings = Belt.List.reduce(zippedParameterList, defaultBindings, (a, (p, e)) => - a->Belt.Map.String.set(p, e->EValue) + a->Belt.Map.String.set(p, e->T.EValue) ) let newExpression = Builder.passToFunction( "$$bindExpression", From 7e4477aeda4f9e4b169f72cd300e7a5648800031 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Mon, 25 Apr 2022 10:00:27 -0400 Subject: [PATCH 18/53] Format Reducer code Value: [0.0000001 to 0.0005] --- packages/squiggle-lang/src/js/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index c8731b0f..ded1581e 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -81,7 +81,9 @@ function tag(x: a, y: b): tagged { return { tag: x, value: y }; } -export abstract class internalCode { protected opaque!: any }; /* simulate opaque types */ +export abstract class internalCode { + protected opaque!: any; +} /* simulate opaque types */ export type squiggleExpression = | tagged<"symbol", string> From d60aaa57f7333c6e04f468ef102b34293586ecc5 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Mon, 25 Apr 2022 10:10:07 -0400 Subject: [PATCH 19/53] Get tests to pass for Reducer code Value: [0.0001 to 0.04] --- packages/squiggle-lang/src/js/index.ts | 5 +---- packages/squiggle-lang/src/rescript/TypescriptInterface.res | 3 +++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index ded1581e..bed78695 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -10,6 +10,7 @@ import { continuousShape, discreteShape, distributionErrorToString, + internalCode, } from "../rescript/TypescriptInterface.gen"; export { makeSampleSetDist, @@ -81,10 +82,6 @@ function tag(x: a, y: b): tagged { return { tag: x, value: y }; } -export abstract class internalCode { - protected opaque!: any; -} /* simulate opaque types */ - export type squiggleExpression = | tagged<"symbol", string> | tagged<"string", string> diff --git a/packages/squiggle-lang/src/rescript/TypescriptInterface.res b/packages/squiggle-lang/src/rescript/TypescriptInterface.res index 8704bf5e..e200fbea 100644 --- a/packages/squiggle-lang/src/rescript/TypescriptInterface.res +++ b/packages/squiggle-lang/src/rescript/TypescriptInterface.res @@ -54,3 +54,6 @@ let errorValueToString = Reducer_ErrorValue.errorToString @genType let distributionErrorToString = DistributionTypes.Error.toString + +@genType +type internalCode = ReducerInterface_ExpressionValue.internalCode From d00834bbe0f8f8f005b15819dc2369f94ed9e859 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 17:39:38 +0200 Subject: [PATCH 20/53] fix spelling - PR#366 --- .../Reducer/Reducer_MathJs/Reducer_MathJsParse_test.res | 2 +- .../squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res | 2 +- 2 files changed, 2 insertions(+), 2 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 988d5a88..a79ff024 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 @@ -25,7 +25,7 @@ module MyOnly = { } describe("MathJs parse", () => { - describe("literals operators paranthesis", () => { + describe("literals operators parenthesis", () => { testParse("1", "1") testParse("'hello'", "'hello'") testParse("true", "true") diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res index 4baee94d..f005c1fc 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res @@ -7,7 +7,7 @@ open Reducer_TestHelpers There is a second version of inspect that takes a label, which will print out the label and the value. - inpsectPerformace(expr, label) will print out the value of expr, the label, and the time it took to evaluate expr. + inspectPerformace(expr, label) will print out the value of expr, the label, and the time it took to evaluate expr. */ describe("Debugging", () => { testEvalToBe("inspect(1)", "Ok(1)") From 6878523186b32cdd74d5600b086ae96866d8c8c5 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 18:27:04 +0200 Subject: [PATCH 21/53] cancel performance hook --- .../Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res | 12 +++++++----- 1 file changed, 7 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 e107016f..47c39140 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 @@ -54,11 +54,13 @@ let callInternal = (call: functionCall): result<'b, errorValue> => { } let inspectPerformance = (value: expressionValue, label: string) => { - let _ = %raw("{performance} = require('perf_hooks')") - let start = %raw(`performance.now()`) - let finish = %raw(`performance.now()`) - let performance = finish - start - Js.log(`${label}: ${value->toString} performance: ${Js.String.make(performance)}ms`) + // let _ = %raw("{performance} = require('perf_hooks')") + // let start = %raw(`performance.now()`) + // let finish = %raw(`performance.now()`) + // let performance = finish - start + // Js.log(`${label}: ${value->toString} performance: ${Js.String.make(performance)}ms`) + // TODO find a way of failing the hook gracefully, also needs a block parameter + Js.log(`${label}: ${value->toString}`) value->Ok } From 7d4e3072b89696301ca16287ba942f247a813df1 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 25 Apr 2022 18:35:15 +0200 Subject: [PATCH 22/53] commite related issue note --- .../Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res | 4 ++++ 1 file changed, 4 insertions(+) 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 47c39140..3e365fd4 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 @@ -53,6 +53,10 @@ let callInternal = (call: functionCall): result<'b, errorValue> => { value->Ok } + /* + NOTE: This function is cancelled. The related issue is + https://github.com/webpack/webpack/issues/13435 + */ let inspectPerformance = (value: expressionValue, label: string) => { // let _ = %raw("{performance} = require('perf_hooks')") // let start = %raw(`performance.now()`) From 54f8b10a9577a376cfd67e35f425c957f37248ae Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Wed, 27 Apr 2022 22:00:42 +0200 Subject: [PATCH 23/53] Reducer: Environment (Give environement to all function dispatches) - closes #169 --- .../__tests__/Reducer/Reducer_TestHelpers.res | 13 +- .../src/rescript/Reducer/Reducer.res | 7 +- .../src/rescript/Reducer/Reducer.resi | 39 +++--- .../Reducer_Dispatch_BuiltIn.res | 6 +- .../Reducer_Dispatch_BuiltInMacros.res | 5 +- .../Reducer_Expression/Reducer_Expression.res | 114 +++++++++--------- .../ReducerInterface_ExpressionValue.res | 8 ++ .../ReducerInterface_ExternalLibrary.res | 4 +- .../ReducerInterface_GenericDistribution.res | 6 +- .../ReducerInterface_GenericDistribution.resi | 2 +- 10 files changed, 119 insertions(+), 85 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res index 581f6c8a..c56d4130 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res @@ -1,9 +1,17 @@ module Expression = Reducer.Expression module ExpressionValue = ReducerInterface.ExpressionValue +module ErrorValue = Reducer_ErrorValue open Jest open Expect +let unwrapRecord = rValue => + rValue->Belt.Result.flatMap(value => switch value { + | ExpressionValue.EvRecord(aRecord) => Ok(aRecord) + | _ => ErrorValue.RETodo("TODO: External bindings must be returned")->Error + } +) + let expectParseToBe = (expr: string, answer: string) => Reducer.parse(expr)->Expression.toStringResult->expect->toBe(answer) @@ -17,7 +25,7 @@ let expectEvalToBe = (expr: string, answer: string) => Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer) let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) => - Reducer.evaluateUsingExternalBindings(expr, bindings) + Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~isPartial=None, ~environment=None) ->ExpressionValue.toStringResult ->expect ->toBe(answer) @@ -27,7 +35,8 @@ let expectEvalPartialBindingsToBe = ( bindings: Reducer.externalBindings, answer: string, ) => - Reducer.evaluatePartialUsingExternalBindings(expr, bindings) + Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~isPartial=Some(true), ~environment=None) + ->unwrapRecord ->ExpressionValue.toStringResultRecord ->expect ->toBe(answer) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res index 63e1f3a7..a403ccd3 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res @@ -5,11 +5,12 @@ module Extra = Reducer_Extra module Js = Reducer_Js module MathJs = Reducer_MathJs +type environment = ReducerInterface_ExpressionValue.environment +type errorValue = Reducer_ErrorValue.errorValue type expressionValue = ReducerInterface_ExpressionValue.expressionValue type externalBindings = ReducerInterface_ExpressionValue.externalBindings -let evaluate = Expression.eval -let evaluateUsingExternalBindings = Expression.evalUsingExternalBindings -let evaluatePartialUsingExternalBindings = Expression.evalPartialUsingExternalBindings +let evaluate = Expression.evaluate +let evaluateUsingOptions = Expression.evaluateUsingOptions let parse = Expression.parse let parseOuter = Expression.parseOuter let parsePartial = Expression.parsePartial diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi index 8bbfc0b5..d71f9a5a 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi @@ -5,22 +5,29 @@ module Extra = Reducer_Extra module Js = Reducer_Js module MathJs = Reducer_MathJs -@genType +@genType +type environment = ReducerInterface_ExpressionValue.environment +@genType +type errorValue = Reducer_ErrorValue.errorValue +@genType type expressionValue = ReducerInterface_ExpressionValue.expressionValue -@genType +@genType type externalBindings = ReducerInterface_ExpressionValue.externalBindings -@genType -let evaluate: string => result -@genType -let evaluateUsingExternalBindings: ( + +@genType +let evaluateUsingOptions: ( + ~environment: option< + QuriSquiggleLang.ReducerInterface_ExpressionValue.environment, + >, + ~externalBindings: option< + QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings, + >, + ~isPartial: option, string, - externalBindings, -) => result -@genType -let evaluatePartialUsingExternalBindings: ( - string, - externalBindings, -) => result -let parse: string => result -let parseOuter: string => result -let parsePartial: string => result +) => result +@genType +let evaluate: string => result + +let parse: string => result +let parseOuter: string => result +let parsePartial: string => result 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 3e365fd4..3733d7e2 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 @@ -11,7 +11,7 @@ open Reducer_ErrorValue exception TestRescriptException -let callInternal = (call: functionCall): result<'b, errorValue> => { +let callInternal = (call: functionCall, _environment): result<'b, errorValue> => { let callMathJs = (call: functionCall): result<'b, errorValue> => switch call { | ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests @@ -85,12 +85,12 @@ let callInternal = (call: functionCall): result<'b, errorValue> => { /* Reducer uses Result monad while reducing expressions */ -let dispatch = (call: functionCall): result => +let dispatch = (call: functionCall, environment): result => try { let (fn, args) = call // There is a bug that prevents string match in patterns // So we have to recreate a copy of the string - ExternalLibrary.dispatch((Js.String.make(fn), args), callInternal) + ExternalLibrary.dispatch((Js.String.make(fn), args), environment, callInternal) } catch { | Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error | _ => RETodo("unhandled rescript exception")->Error diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index 5facc9e7..185897e9 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -10,10 +10,12 @@ module Result = Belt.Result open Reducer_ErrorValue type expression = ExpressionT.expression +type environment = ExpressionValue.environment type reducerFn = ( expression, ExpressionT.bindings, + environment, ) => result let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings): result< @@ -101,6 +103,7 @@ let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings let dispatchMacroCall = ( list: list, bindings: ExpressionT.bindings, + environment, reduceExpression: reducerFn, ): result => { let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => { @@ -114,7 +117,7 @@ let dispatchMacroCall = ( let rNewValue = rNewExpressionToReduce->Result.flatMap(newExpressionToReduce => - reduceExpression(newExpressionToReduce, bindings) + reduceExpression(newExpressionToReduce, bindings, environment) ) let rNewExpression = rNewValue->Result.map(newValue => ExpressionT.EValue(newValue)) 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 d27ece78..052648ed 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 @@ -8,9 +8,12 @@ module T = Reducer_Expression_T open Reducer_ErrorValue +type environment = ReducerInterface_ExpressionValue.environment +type errorValue = Reducer_ErrorValue.errorValue type expression = T.expression -type expressionValue = ExpressionValue.expressionValue -type internalCode = ExpressionValue.internalCode +type expressionValue = ReducerInterface_ExpressionValue.expressionValue +type externalBindings = ReducerInterface_ExpressionValue.externalBindings +type internalCode = ReducerInterface_ExpressionValue.internalCode type t = expression external castExpressionToInternalCode: expression => internalCode = "%identity" @@ -57,19 +60,20 @@ let defaultBindings: T.bindings = Belt.Map.String.empty /* Recursively evaluate/reduce the expression (Lisp AST) */ -let rec reduceExpression = (expression: t, bindings: T.bindings): result => { +let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result => { /* 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 => - Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, reduceExpression) + let doMacroCall = (list: list, bindings: T.bindings, environment: environment): result => + Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, environment, reduceExpression) let applyParametersToLambda = ( internal: internalCode, parameters: array, args: list, + environment ): result => { let expr = castInternalCodeToExpression(internal) let parameterList = parameters->Belt.List.fromArray @@ -81,22 +85,22 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result): result => + let reduceValueList = (valueList: list, environment): result => switch valueList { - | list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch + | list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment) // "(lambda(x=>internal) param)" | list{EvLambda((parameters, internal)), ...args} => - applyParametersToLambda(internal, parameters, args) + applyParametersToLambda(internal, parameters, args, environment) | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok } - let rec seekMacros = (expression: t, bindings: T.bindings): result => + let rec seekMacros = (expression: t, bindings: T.bindings, environment): result => switch expression { | T.EValue(_value) => expression->Ok | T.EBindings(_value) => expression->Ok @@ -108,17 +112,17 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result racc->Result.flatMap(acc => { each - ->seekMacros(bindings) + ->seekMacros(bindings, environment) ->Result.flatMap(newNode => { acc->Belt.List.add(newNode)->Ok }) }) ) - racc->Result.flatMap(acc => acc->doMacroCall(bindings)) + racc->Result.flatMap(acc => acc->doMacroCall(bindings, environment)) } } - let rec reduceExpandedExpression = (expression: t): result => + let rec reduceExpandedExpression = (expression: t, environment): result => switch expression { | T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) => EvLambda((parameters, functionDefinition->castExpressionToInternalCode))->Ok @@ -130,36 +134,36 @@ let rec reduceExpression = (expression: t, bindings: T.bindings): result racc->Result.flatMap(acc => { each - ->reduceExpandedExpression + ->reduceExpandedExpression(environment) ->Result.flatMap(newNode => { acc->Belt.List.add(newNode)->Ok }) }) ) - racc->Result.flatMap(acc => acc->reduceValueList) + racc->Result.flatMap(acc => acc->reduceValueList(environment)) } | EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error | EParameters(_parameters) => RETodo("Error: Lambda Parameters cannot be reduced to values")->Error } - let rExpandedExpression: result = expression->seekMacros(bindings) + let rExpandedExpression: result = expression->seekMacros(bindings, environment) rExpandedExpression->Result.flatMap(expandedExpression => - expandedExpression->reduceExpandedExpression + expandedExpression->reduceExpandedExpression(environment) ) } -let evalUsingExternalBindingsExpression_ = (aExpression, bindings): result => - reduceExpression(aExpression, bindings) +let evalUsingExternalBindingsExpression_ = (aExpression, bindings, environment): result => + reduceExpression(aExpression, bindings, environment) /* Evaluates MathJs code via Reducer using bindings and answers the result. When bindings are used, the code is a partial code as if it is cut from a larger code. Therefore all statements are assignments. */ -let evalPartialUsingExternalBindings_ = (codeText: string, bindings: T.bindings) => { +let evalPartial_ = (codeText: string, bindings: T.bindings, environment: environment) => { parsePartial(codeText)->Result.flatMap(expression => - expression->evalUsingExternalBindingsExpression_(bindings) + expression->evalUsingExternalBindingsExpression_(bindings, environment) ) } @@ -168,23 +172,12 @@ let evalPartialUsingExternalBindings_ = (codeText: string, bindings: T.bindings) When bindings are used, the code is a partial code as if it is cut from a larger code. Therefore all statments are assignments. */ -let evalOuterWBindings_ = (codeText: string, bindings: T.bindings) => { +let evalOuter_ = (codeText: string, bindings: T.bindings, environment: environment) => { parseOuter(codeText)->Result.flatMap(expression => - expression->evalUsingExternalBindingsExpression_(bindings) + expression->evalUsingExternalBindingsExpression_(bindings, environment) ) } -/* - Evaluates MathJs code and bindings via Reducer and answers the result -*/ -let eval = (codeText: string) => { - parse(codeText)->Result.flatMap(expression => - expression->evalUsingExternalBindingsExpression_(defaultBindings) - ) -} - -type externalBindings = ReducerInterface.ExpressionValue.externalBindings //Js.Dict.t - let externalBindingsToBindings = (externalBindings: externalBindings): T.bindings => { let keys = Js.Dict.keys(externalBindings) keys->Belt.Array.reduce(defaultBindings, (acc, key) => { @@ -192,28 +185,41 @@ let externalBindingsToBindings = (externalBindings: externalBindings): T.binding acc->Belt.Map.String.set(key, T.EValue(value)) }) } -/* - Evaluates code with external bindings. External bindings are a record of expression values. -*/ -let evalUsingExternalBindings = (code: string, externalBindings: externalBindings) => { - let bindings = externalBindings->externalBindingsToBindings - evalOuterWBindings_(code, bindings) + +let evaluateUsingOptions = ( + ~environment: option, + ~externalBindings: option, + ~isPartial: option, + code: string): result => { + + let anEnvironment = switch environment { + | Some(env) => env + | None => ReducerInterface_ExpressionValue.defaultEnvironment + } + + let anExternalBindings = switch externalBindings { + | Some(bindings) => bindings + | None => ReducerInterface_ExpressionValue.defaultExternalBindings + } + + let anIsPartial = switch isPartial { + | Some(isPartial) => isPartial + | None => false + } + + let bindings = anExternalBindings->externalBindingsToBindings + + if anIsPartial { + evalPartial_(code, bindings, anEnvironment) + } else { + evalOuter_(code, bindings, anEnvironment) + } } /* - Evaluates code with external bindings. External bindings are a record of expression values. - The code is a partial code as if it is cut from a larger code. Therefore all statments are assignments. + Evaluates MathJs code and bindings via Reducer and answers the result */ -let evalPartialUsingExternalBindings = (code: string, externalBindings: externalBindings): result< - externalBindings, - 'e, -> => { - let bindings = externalBindings->externalBindingsToBindings - let answer = evalPartialUsingExternalBindings_(code, bindings) - answer->Result.flatMap(answer => - switch answer { - | EvRecord(aRecord) => Ok(aRecord) - | _ => RETodo("TODO: External bindings must be returned")->Error - } - ) +let evaluate = (code: string): result => { + evaluateUsingOptions(~environment=None, ~externalBindings=None, ~isPartial=None, code) } +let eval = evaluate diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 6c15536b..96068dca 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -22,6 +22,9 @@ type rec expressionValue = @genType type externalBindings = Js.Dict.t +@genType +let defaultExternalBindings: externalBindings = Js.Dict.empty() + type functionCall = (string, array) @@ -84,3 +87,8 @@ let toStringResultRecord = x => | Ok(a) => `Ok(${toStringRecord(a)})` | Error(m) => `Error(${ErrorValue.errorToString(m)})` } + +@genType +type environment = {dummy: int} +@genType +let defaultEnvironment: environment = {dummy: 0} diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res index 84d37d95..fde0faf2 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res @@ -14,8 +14,8 @@ type expressionValue = ExpressionValue.expressionValue Map external calls of Reducer */ -let dispatch = (call: ExpressionValue.functionCall, chain): result => - ReducerInterface_GenericDistribution.dispatch(call) |> E.O.default(chain(call)) +let dispatch = (call: ExpressionValue.functionCall, environment, chain): result => + ReducerInterface_GenericDistribution.dispatch(call, environment) |> E.O.default(chain(call, environment)) /* If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally. diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index f39dc932..5ed33809 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -180,7 +180,7 @@ module Math = { let e = 2.718281828459 } -let dispatchToGenericOutput = (call: ExpressionValue.functionCall): option< +let dispatchToGenericOutput = (call: ExpressionValue.functionCall, _environment): option< DistributionOperation.outputType, > => { let (fnName, args) = call @@ -266,6 +266,6 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result< | GenDistError(err) => Error(REDistributionError(err)) } -let dispatch = call => { - dispatchToGenericOutput(call)->E.O2.fmap(genericOutputToReducerValue) +let dispatch = (call, environment) => { + dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue) } diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi index fc7ebabc..26464d44 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi @@ -1,3 +1,3 @@ -let dispatch: ReducerInterface_ExpressionValue.functionCall => option< +let dispatch: (ReducerInterface_ExpressionValue.functionCall, ReducerInterface_ExpressionValue.environment) => option< result, > From 5c1ce71a40d838cb29c229976b065e061728d464 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Wed, 27 Apr 2022 22:09:25 +0200 Subject: [PATCH 24/53] fix TypescriptInterface.res --- packages/squiggle-lang/src/rescript/TypescriptInterface.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/rescript/TypescriptInterface.res b/packages/squiggle-lang/src/rescript/TypescriptInterface.res index 5e2a59b6..a16e6875 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 -let evaluateUsingExternalBindings = Reducer.evaluateUsingExternalBindings +let evaluateUsingOptions = Reducer.evaluateUsingOptions @genType type expressionValue = ReducerInterface_ExpressionValue.expressionValue From 7b052ee3c34a87c5d9edd0a1325f5a806ff12378 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Wed, 27 Apr 2022 22:24:06 +0200 Subject: [PATCH 25/53] format --- .../__tests__/Reducer/Reducer_TestHelpers.res | 25 +++++++--- .../src/rescript/Reducer/Reducer.resi | 20 ++++---- .../Reducer_Dispatch_BuiltIn.res | 2 +- .../Reducer_Expression/Reducer_Expression.res | 48 ++++++++++++------- .../ReducerInterface_ExpressionValue.res | 1 - .../ReducerInterface_ExternalLibrary.res | 9 +++- .../ReducerInterface_GenericDistribution.resi | 7 +-- 7 files changed, 68 insertions(+), 44 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res index c56d4130..a38624dc 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res @@ -6,11 +6,12 @@ open Jest open Expect let unwrapRecord = rValue => - rValue->Belt.Result.flatMap(value => switch value { - | ExpressionValue.EvRecord(aRecord) => Ok(aRecord) - | _ => ErrorValue.RETodo("TODO: External bindings must be returned")->Error - } -) + rValue->Belt.Result.flatMap(value => + switch value { + | ExpressionValue.EvRecord(aRecord) => Ok(aRecord) + | _ => ErrorValue.RETodo("TODO: External bindings must be returned")->Error + } + ) let expectParseToBe = (expr: string, answer: string) => Reducer.parse(expr)->Expression.toStringResult->expect->toBe(answer) @@ -25,7 +26,12 @@ let expectEvalToBe = (expr: string, answer: string) => Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer) let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) => - Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~isPartial=None, ~environment=None) + Reducer.evaluateUsingOptions( + expr, + ~externalBindings=Some(bindings), + ~isPartial=None, + ~environment=None, + ) ->ExpressionValue.toStringResult ->expect ->toBe(answer) @@ -35,7 +41,12 @@ let expectEvalPartialBindingsToBe = ( bindings: Reducer.externalBindings, answer: string, ) => - Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~isPartial=Some(true), ~environment=None) + Reducer.evaluateUsingOptions( + expr, + ~externalBindings=Some(bindings), + ~isPartial=Some(true), + ~environment=None, + ) ->unwrapRecord ->ExpressionValue.toStringResultRecord ->expect diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi index d71f9a5a..8ea6047a 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi @@ -5,27 +5,23 @@ module Extra = Reducer_Extra module Js = Reducer_Js module MathJs = Reducer_MathJs -@genType +@genType type environment = ReducerInterface_ExpressionValue.environment -@genType +@genType type errorValue = Reducer_ErrorValue.errorValue -@genType +@genType type expressionValue = ReducerInterface_ExpressionValue.expressionValue -@genType +@genType type externalBindings = ReducerInterface_ExpressionValue.externalBindings -@genType +@genType let evaluateUsingOptions: ( - ~environment: option< - QuriSquiggleLang.ReducerInterface_ExpressionValue.environment, - >, - ~externalBindings: option< - QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings, - >, + ~environment: option, + ~externalBindings: option, ~isPartial: option, string, ) => result -@genType +@genType let evaluate: string => result let parse: string => result 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 3733d7e2..93960cf6 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 @@ -56,7 +56,7 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> => /* NOTE: This function is cancelled. The related issue is https://github.com/webpack/webpack/issues/13435 - */ + */ let inspectPerformance = (value: expressionValue, label: string) => { // let _ = %raw("{performance} = require('perf_hooks')") // let start = %raw(`performance.now()`) 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 052648ed..1713476f 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 @@ -60,20 +60,26 @@ let defaultBindings: T.bindings = Belt.Map.String.empty /* Recursively evaluate/reduce the expression (Lisp AST) */ -let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result => { +let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result< + expressionValue, + 'e, +> => { /* 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, environment: environment): result => + let doMacroCall = (list: list, bindings: T.bindings, environment: environment): result< + t, + 'e, + > => Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, environment, reduceExpression) let applyParametersToLambda = ( internal: internalCode, parameters: array, args: list, - environment + environment, ): result => { let expr = castInternalCodeToExpression(internal) let parameterList = parameters->Belt.List.fromArray @@ -91,9 +97,13 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en /* After reducing each level of expression(Lisp AST), we have a value list to evaluate */ - let reduceValueList = (valueList: list, environment): result => + let reduceValueList = (valueList: list, environment): result< + expressionValue, + 'e, + > => switch valueList { - | list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment) + | list{EvCall(fName), ...args} => + (fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment) // "(lambda(x=>internal) param)" | list{EvLambda((parameters, internal)), ...args} => applyParametersToLambda(internal, parameters, args, environment) @@ -153,8 +163,10 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en ) } -let evalUsingExternalBindingsExpression_ = (aExpression, bindings, environment): result => - reduceExpression(aExpression, bindings, environment) +let evalUsingExternalBindingsExpression_ = (aExpression, bindings, environment): result< + expressionValue, + 'e, +> => reduceExpression(aExpression, bindings, environment) /* Evaluates MathJs code via Reducer using bindings and answers the result. @@ -187,24 +199,24 @@ let externalBindingsToBindings = (externalBindings: externalBindings): T.binding } let evaluateUsingOptions = ( - ~environment: option, - ~externalBindings: option, - ~isPartial: option, - code: string): result => { - + ~environment: option, + ~externalBindings: option, + ~isPartial: option, + code: string, +): result => { let anEnvironment = switch environment { - | Some(env) => env - | None => ReducerInterface_ExpressionValue.defaultEnvironment + | Some(env) => env + | None => ReducerInterface_ExpressionValue.defaultEnvironment } let anExternalBindings = switch externalBindings { - | Some(bindings) => bindings - | None => ReducerInterface_ExpressionValue.defaultExternalBindings + | Some(bindings) => bindings + | None => ReducerInterface_ExpressionValue.defaultExternalBindings } let anIsPartial = switch isPartial { - | Some(isPartial) => isPartial - | None => false + | Some(isPartial) => isPartial + | None => false } let bindings = anExternalBindings->externalBindingsToBindings diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 96068dca..7e8d1150 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -25,7 +25,6 @@ type externalBindings = Js.Dict.t @genType let defaultExternalBindings: externalBindings = Js.Dict.empty() - type functionCall = (string, array) let rec toString = aValue => diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res index fde0faf2..0bdb0748 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res @@ -14,8 +14,13 @@ type expressionValue = ExpressionValue.expressionValue Map external calls of Reducer */ -let dispatch = (call: ExpressionValue.functionCall, environment, chain): result => - ReducerInterface_GenericDistribution.dispatch(call, environment) |> E.O.default(chain(call, environment)) +let dispatch = (call: ExpressionValue.functionCall, environment, chain): result< + expressionValue, + 'e, +> => + ReducerInterface_GenericDistribution.dispatch(call, environment) |> E.O.default( + chain(call, environment), + ) /* If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally. diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi index 26464d44..7f26a610 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi @@ -1,3 +1,4 @@ -let dispatch: (ReducerInterface_ExpressionValue.functionCall, ReducerInterface_ExpressionValue.environment) => option< - result, -> +let dispatch: ( + ReducerInterface_ExpressionValue.functionCall, + ReducerInterface_ExpressionValue.environment, +) => option> From 8e318a8aa9e4306e165475a334831f86477d4e9c Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Thu, 28 Apr 2022 18:35:09 +0200 Subject: [PATCH 26/53] refactor reducer removed some extra array references rename Builder to ExpressionBuilder Expression Builder Trash Warning remove parsePartial/Outer, add context to lambda format module Bindings simplify types module Macro reduceValueList do macro call result map bindings stop replacing on macro calls Macro Test doBindStatement bind a statement bindings tested. TODO bind shadowing in lambda block tests defined block tests defined blocks tested macro lambda test defined --- .../Reducer_Dispatch_BuiltInMacros_test.res | 121 ++++++++ .../Reducer_Expression_test.res | 6 + .../__tests__/Reducer/Reducer_TestHelpers.res | 53 +--- .../Reducer/Reducer_TestMacroHelpers.res | 81 ++++++ .../Reducer/Reducer_externalBindings_test.res | 91 +++--- .../Reducer_functionAssignment_test.res | 4 +- .../__tests__/Reducer/Reducer_test.res | 51 ++-- .../ReducerInterface_Distribution_test.res | 26 +- .../ReducerInterface_ExpressionValue_test.res | 4 +- .../src/rescript/Reducer/Reducer.res | 2 - .../src/rescript/Reducer/Reducer.resi | 3 - .../Reducer_Dispatch_BuiltIn.res | 18 ++ .../Reducer_Dispatch_BuiltInMacros.res | 272 ++++++++---------- .../Reducer_Expression/Reducer_Expression.res | 227 ++++----------- .../Reducer_Expression_Bindings.res | 73 +++++ .../Reducer_Expression_Builder.res | 16 -- .../Reducer_Expression_ExpressionBuilder.res | 60 ++++ .../Reducer_Expression_Lambda.res | 35 +++ .../Reducer_Expression_Macro.res | 35 +++ .../Reducer_Expression_T.res | 50 +++- .../Reducer_MathJs_ToExpression.res | 149 +++------- .../ReducerInterface_ExpressionValue.res | 37 +-- 22 files changed, 800 insertions(+), 614 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_Expression/Reducer_Expression_test.res create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res create mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res delete mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res create mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res create mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res create mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res new file mode 100644 index 00000000..ecf97697 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res @@ -0,0 +1,121 @@ +open Jest +// open Expect + +open Reducer_Expression_ExpressionBuilder +open Reducer_TestMacroHelpers +module ExpressionT = Reducer_Expression_T + +let exampleExpression = eNumber(1.) +let exampleExpressionY = eSymbol("y") +let exampleStatement = eLetStatement("y", eNumber(1.)) +let exampleStatementX = eLetStatement("y", eSymbol("x")) +let exampleStatementZ = eLetStatement("z", eSymbol("y")) + +// If it is not a mactro then it is not expanded +testMacro([], exampleExpression, "Ok(1)") + +describe("bindStatement", () => { + // A statement is bound by the bindings created by the previous statement + testMacro([], eBindStatement(eBindings([]), exampleStatement), "Ok((:$setBindings {} :y 1))") + // Then it answers the bindings for the next statement when reduced + testMacroEval([], eBindStatement(eBindings([]), exampleStatement), "Ok({y: 1})") + // Now let's feed a binding to see what happens + testMacro( + [], + eBindStatement(eBindings([("x", EvNumber(2.))]), exampleStatementX), + "Ok((:$setBindings {x: 2} :y 2))", + ) + // An expression does not return a binding, thus error + testMacro([], eBindStatement(eBindings([]), exampleExpression), "Error(Assignment expected)") + // When bindings from previous statement are missing the context is injected. This must be the first statement of a block + testMacro( + [("z", EvNumber(99.))], + eBindStatementDefault(exampleStatement), + "Ok((:$setBindings {z: 99} :y 1))", + ) +}) + +describe("bindExpression", () => { + // x is simply bound in the expression + testMacro([], eBindExpression(eBindings([("x", EvNumber(2.))]), eSymbol("x")), "Ok(2)") + // When an let statement is the end expression then bindings are returned + testMacro( + [], + eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatement), + "Ok((:$exportBindings (:$setBindings {x: 2} :y 1)))", + ) + // Now let's reduce that expression + testMacroEval( + [], + eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatement), + "Ok({x: 2,y: 1})", + ) + // When bindings are missing the context is injected. This must be the first and last statement of a block + testMacroEval( + [("z", EvNumber(99.))], + eBindExpressionDefault(exampleStatement), + "Ok({y: 1,z: 99})", + ) +}) + +describe("block", () => { + // Block with a single expression + testMacro([], eBlock(list{exampleExpression}), "Ok((:$$bindExpression 1))") + testMacroEval([], eBlock(list{exampleExpression}), "Ok(1)") + // Block with a single statement + testMacro([], eBlock(list{exampleStatement}), "Ok((:$$bindExpression (:$let :y 1)))") + testMacroEval([], eBlock(list{exampleStatement}), "Ok({y: 1})") + // Block with a statement and an expression + testMacro( + [], + eBlock(list{exampleStatement, exampleExpressionY}), + "Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) :y))", + ) + testMacroEval([], eBlock(list{exampleStatement, exampleExpressionY}), "Ok(1)") + // Block with a statement and another statement + testMacro( + [], + eBlock(list{exampleStatement, exampleStatementZ}), + "Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) (:$let :z :y)))", + ) + testMacroEval([], eBlock(list{exampleStatement, exampleStatementZ}), "Ok({y: 1,z: 1})") + // Block inside a block + testMacro( + [], + eBlock(list{eBlock(list{exampleExpression})}), + "Ok((:$$bindExpression (:$$block 1)))", + ) + testMacroEval([], eBlock(list{eBlock(list{exampleExpression})}), "Ok(1)") + // Block assigned to a variable + testMacro( + [], + eBlock(list{eLetStatement("z", eBlock(list{eBlock(list{exampleExpressionY})}))}), + "Ok((:$$bindExpression (:$let :z (:$$block (:$$block :y)))))", + ) + testMacroEval( + [], + eBlock(list{eLetStatement("z", eBlock(list{eBlock(list{exampleExpressionY})}))}), + "Ok({z: :y})", + ) + // Empty block + testMacro([], eBlock(list{}), "Ok(:undefined block)") //TODO: should be an error +}) + +describe("lambda", () => { + // assign a lambda to a variable + let lambdaExpression = eFunction("$$lambda", list{eArrayString(["y"]), exampleExpressionY}) + testMacro([], lambdaExpression, "Ok(lambda(y=>internal))") + // call a lambda + let callLambdaExpression = list{lambdaExpression, eNumber(1.)}->ExpressionT.EList + testMacro([], callLambdaExpression, "Ok(((:$$lambda [y] :y) 1))") + testMacroEval([], callLambdaExpression, "Ok(1)") + // Parameters shadow the outer scope + testMacroEval([("y", EvNumber(666.))], callLambdaExpression, "Ok(1)") + // When not shadowed by the parameters, the outer scope variables are available + let lambdaExpression = eFunction( + "$$lambda", + list{eArrayString(["z"]), eFunction("add", list{eSymbol("y"), eSymbol("z")})}, + ) + let callLambdaExpression = eList(list{lambdaExpression, eNumber(1.)}) + testMacroEval([("y", EvNumber(666.))], callLambdaExpression, "Ok(667)") +}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Expression/Reducer_Expression_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Expression/Reducer_Expression_test.res new file mode 100644 index 00000000..f20d95f7 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Expression/Reducer_Expression_test.res @@ -0,0 +1,6 @@ +open Jest +open Expect + +test("dummy", () => { + expect(true)->toBe(true) +}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res index a38624dc..766acd43 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestHelpers.res @@ -1,4 +1,4 @@ -module Expression = Reducer.Expression +module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface.ExpressionValue module ErrorValue = Reducer_ErrorValue @@ -14,47 +14,18 @@ let unwrapRecord = rValue => ) let expectParseToBe = (expr: string, answer: string) => - Reducer.parse(expr)->Expression.toStringResult->expect->toBe(answer) - -let expectParseOuterToBe = (expr: string, answer: string) => - Reducer.parseOuter(expr)->Expression.toStringResult->expect->toBe(answer) - -let expectParsePartialToBe = (expr: string, answer: string) => - Reducer.parsePartial(expr)->Expression.toStringResult->expect->toBe(answer) + Reducer.parse(expr)->ExpressionT.toStringResult->expect->toBe(answer) let expectEvalToBe = (expr: string, answer: string) => Reducer.evaluate(expr)->ExpressionValue.toStringResult->expect->toBe(answer) let expectEvalBindingsToBe = (expr: string, bindings: Reducer.externalBindings, answer: string) => - Reducer.evaluateUsingOptions( - expr, - ~externalBindings=Some(bindings), - ~isPartial=None, - ~environment=None, - ) + Reducer.evaluateUsingOptions(expr, ~externalBindings=Some(bindings), ~environment=None) ->ExpressionValue.toStringResult ->expect ->toBe(answer) -let expectEvalPartialBindingsToBe = ( - expr: string, - bindings: Reducer.externalBindings, - answer: string, -) => - Reducer.evaluateUsingOptions( - expr, - ~externalBindings=Some(bindings), - ~isPartial=Some(true), - ~environment=None, - ) - ->unwrapRecord - ->ExpressionValue.toStringResultRecord - ->expect - ->toBe(answer) - let testParseToBe = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) -let testParseOuterToBe = (expr, answer) => test(expr, () => expectParseOuterToBe(expr, answer)) -let testParsePartialToBe = (expr, answer) => test(expr, () => expectParsePartialToBe(expr, answer)) let testDescriptionParseToBe = (desc, expr, answer) => test(desc, () => expectParseToBe(expr, answer)) @@ -62,34 +33,16 @@ let testEvalToBe = (expr, answer) => test(expr, () => expectEvalToBe(expr, answe let testDescriptionEvalToBe = (desc, expr, answer) => test(desc, () => expectEvalToBe(expr, answer)) let testEvalBindingsToBe = (expr, bindingsList, answer) => test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)) -let testEvalPartialBindingsToBe = (expr, bindingsList, answer) => - test(expr, () => expectEvalPartialBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)) module MySkip = { let testParseToBe = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) - let testParseOuterToBe = (expr, answer) => - Skip.test(expr, () => expectParseOuterToBe(expr, answer)) - let testParsePartialToBe = (expr, answer) => - Skip.test(expr, () => expectParsePartialToBe(expr, answer)) let testEvalToBe = (expr, answer) => Skip.test(expr, () => expectEvalToBe(expr, answer)) let testEvalBindingsToBe = (expr, bindingsList, answer) => Skip.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)) - let testEvalPartialBindingsToBe = (expr, bindingsList, answer) => - Skip.test(expr, () => - expectEvalPartialBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer) - ) } module MyOnly = { let testParseToBe = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer)) - let testParseOuterToBe = (expr, answer) => - Only.test(expr, () => expectParseOuterToBe(expr, answer)) - let testParsePartialToBe = (expr, answer) => - Only.test(expr, () => expectParsePartialToBe(expr, answer)) let testEvalToBe = (expr, answer) => Only.test(expr, () => expectEvalToBe(expr, answer)) let testEvalBindingsToBe = (expr, bindingsList, answer) => Only.test(expr, () => expectEvalBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer)) - let testEvalPartialBindingsToBe = (expr, bindingsList, answer) => - Only.test(expr, () => - expectEvalPartialBindingsToBe(expr, bindingsList->Js.Dict.fromList, answer) - ) } diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res new file mode 100644 index 00000000..af88cac4 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res @@ -0,0 +1,81 @@ +open Jest +open Expect + +module Macro = Reducer_Expression_Macro +module Bindings = Reducer_Expression_Bindings +module Expression = Reducer_Expression +module ExpressionValue = ReducerInterface_ExpressionValue +module T = Reducer_Expression_T + +let testMacro_ = ( + tester, + bindArray: array<(string, ExpressionValue.expressionValue)>, + expr: T.expression, + expectedCode: string, +) => { + let bindings = Belt.Map.String.fromArray(bindArray) + tester(expr->T.toString, () => + expr + ->Macro.expandMacroCall( + bindings, + ExpressionValue.defaultEnvironment, + Expression.reduceExpression, + ) + ->T.toStringResult + ->expect + ->toEqual(expectedCode) + ) +} + +let testMacroEval_ = ( + tester, + bindArray: array<(string, ExpressionValue.expressionValue)>, + expr: T.expression, + expectedValue: string, +) => { + let bindings = Belt.Map.String.fromArray(bindArray) + tester(expr->T.toString, () => + expr + ->Macro.doMacroCall(bindings, ExpressionValue.defaultEnvironment, Expression.reduceExpression) + ->ExpressionValue.toStringResult + ->expect + ->toEqual(expectedValue) + ) +} + +let testMacro = ( + bindArray: array<(string, ExpressionValue.expressionValue)>, + expr: T.expression, + expectedExpr: string, +) => testMacro_(test, bindArray, expr, expectedExpr) +let testMacroEval = ( + bindArray: array<(string, ExpressionValue.expressionValue)>, + expr: T.expression, + expectedValue: string, +) => testMacroEval_(test, bindArray, expr, expectedValue) + +module MySkip = { + let testMacro = ( + bindArray: array<(string, ExpressionValue.expressionValue)>, + expr: T.expression, + expectedExpr: string, + ) => testMacro_(Skip.test, bindArray, expr, expectedExpr) + let testMacroEval = ( + bindArray: array<(string, ExpressionValue.expressionValue)>, + expr: T.expression, + expectedValue: string, + ) => testMacroEval_(Skip.test, bindArray, expr, expectedValue) +} + +module MyOnly = { + let testMacro = ( + bindArray: array<(string, ExpressionValue.expressionValue)>, + expr: T.expression, + expectedExpr: string, + ) => testMacro_(Only.test, bindArray, expr, expectedExpr) + let testMacroEval = ( + bindArray: array<(string, ExpressionValue.expressionValue)>, + expr: T.expression, + expectedValue: string, + ) => testMacroEval_(Only.test, bindArray, expr, expectedValue) +} diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res index ce834ed1..4c2546f4 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res @@ -1,33 +1,34 @@ +// TODO: Reimplement with usual parse open Jest open Reducer_TestHelpers -describe("Parse for Bindings", () => { - testParseOuterToBe("x", "Ok((:$$bindExpression (:$$bindings) :x))") - testParseOuterToBe("x+1", "Ok((:$$bindExpression (:$$bindings) (:add :x 1)))") - testParseOuterToBe( - "y = x+1; y", - "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))", - ) -}) +// describe("Parse for Bindings", () => { +// testParseOuterToBe("x", "Ok((:$$bindExpression (:$$bindings) :x))") +// testParseOuterToBe("x+1", "Ok((:$$bindExpression (:$$bindings) (:add :x 1)))") +// testParseOuterToBe( +// "y = x+1; y", +// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) :y))", +// ) +// }) -describe("Parse Partial", () => { - testParsePartialToBe( - "x", - "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))", - ) - testParsePartialToBe( - "y=x", - "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y :x)) (:$exportVariablesExpression)))", - ) - testParsePartialToBe( - "y=x+1", - "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$exportVariablesExpression)))", - ) - testParsePartialToBe( - "y = x+1; z = y", - "Ok((:$$bindExpression (:$$bindStatement (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$let :z :y)) (:$exportVariablesExpression)))", - ) -}) +// describe("Parse Partial", () => { +// testParsePartialToBe( +// "x", +// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) :x) (:$exportVariablesExpression)))", +// ) +// testParsePartialToBe( +// "y=x", +// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y :x)) (:$exportVariablesExpression)))", +// ) +// testParsePartialToBe( +// "y=x+1", +// "Ok((:$$bindExpression (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$exportVariablesExpression)))", +// ) +// testParsePartialToBe( +// "y = x+1; z = y", +// "Ok((:$$bindExpression (:$$bindStatement (:$$bindStatement (:$$bindings) (:$let :y (:add :x 1))) (:$let :z :y)) (:$exportVariablesExpression)))", +// ) +// }) describe("Eval with Bindings", () => { testEvalBindingsToBe("x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(1)") @@ -39,22 +40,22 @@ describe("Eval with Bindings", () => { Partial code is a partial code fragment that is cut out from a larger code. Therefore it does not end with an expression. */ -describe("Eval Partial", () => { - testEvalPartialBindingsToBe( - // A partial cannot end with an expression - "x", - list{("x", ExpressionValue.EvNumber(1.))}, - "Error(Assignment expected)", - ) - testEvalPartialBindingsToBe("y=x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1, y: 1})") - testEvalPartialBindingsToBe( - "y=x+1", - list{("x", ExpressionValue.EvNumber(1.))}, - "Ok({x: 1, y: 2})", - ) - testEvalPartialBindingsToBe( - "y = x+1; z = y", - list{("x", ExpressionValue.EvNumber(1.))}, - "Ok({x: 1, y: 2, z: 2})", - ) -}) +// describe("Eval Partial", () => { +// testEvalPartialBindingsToBe( +// // A partial cannot end with an expression +// "x", +// list{("x", ExpressionValue.EvNumber(1.))}, +// "Error(Assignment expected)", +// ) +// testEvalPartialBindingsToBe("y=x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1,y: 1})") +// testEvalPartialBindingsToBe( +// "y=x+1", +// list{("x", ExpressionValue.EvNumber(1.))}, +// "Ok({x: 1,y: 2})", +// ) +// testEvalPartialBindingsToBe( +// "y = x+1; z = y", +// list{("x", ExpressionValue.EvNumber(1.))}, +// "Ok({x: 1,y: 2,z: 2})", +// ) +// }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res index 9259dacd..bb3e2220 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionAssignment_test.res @@ -2,8 +2,8 @@ open Jest open Reducer_TestHelpers describe("Parse function assignment", () => { - testParseToBe("f(x)=x", "Ok((:$let :f (:$lambda (x) :x)))") - testParseToBe("f(x)=2*x", "Ok((:$let :f (:$lambda (x) (:multiply 2 :x))))") + testParseToBe("f(x)=x", "Ok((:$$block (:$let :f (:$$lambda [x] (:$$block :x)))))") + testParseToBe("f(x)=2*x", "Ok((:$$block (:$let :f (:$$lambda [x] (:$$block (:multiply 2 :x))))))") //MathJs does not allow blocks in function definitions }) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res index 5514b67c..80468c0f 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_test.res @@ -10,46 +10,39 @@ describe("reducer using mathjs parse", () => { // Those tests toString that we are converting mathjs parse tree to what we need describe("expressions", () => { - 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)))") + testParseToBe("1", "Ok((:$$block 1))") + testParseToBe("(1)", "Ok((:$$block 1))") + testParseToBe("1+2", "Ok((:$$block (:add 1 2)))") + testParseToBe("1+2*3", "Ok((:$$block (: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) - testDescriptionParseToBe("empty", "[]", "Ok(())") - testParseToBe("[1, 2, 3]", "Ok((1 2 3))") - testParseToBe("['hello', 'world']", "Ok(('hello' 'world'))") - testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$atIndex (0 1 2) (1)))") + testDescriptionParseToBe("empty", "[]", "Ok((:$$block ()))") + testParseToBe("[1, 2, 3]", "Ok((:$$block (1 2 3)))") + testParseToBe("['hello', 'world']", "Ok((:$$block ('hello' 'world')))") + testDescriptionParseToBe("index", "([0,1,2])[1]", "Ok((:$$block (:$atIndex (0 1 2) (1))))") }) describe("records", () => { - testDescriptionParseToBe("define", "{a: 1, b: 2}", "Ok((:$constructRecord (('a' 1) ('b' 2))))") + testDescriptionParseToBe( + "define", + "{a: 1, b: 2}", + "Ok((:$$block (:$constructRecord (('a' 1) ('b' 2)))))", + ) testDescriptionParseToBe( "use", "{a: 1, b: 2}.a", - "Ok((:$atIndex (:$constructRecord (('a' 1) ('b' 2))) ('a')))", + "Ok((:$$block (:$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)))", - ) + testParseToBe("1; 2", "Ok((:$$block (:$$block 1 2)))") + testParseToBe("1+1; 2+1", "Ok((:$$block (:$$block (: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((:$$block (:$$block (:$let :x 1) :x)))") + testParseToBe("x=1+1; x+1", "Ok((:$$block (:$$block (:$let :x (:add 1 1)) (:add :x 1))))") }) }) @@ -70,13 +63,13 @@ describe("eval", () => { }) describe("arrays", () => { test("empty array", () => expectEvalToBe("[]", "Ok([])")) - testEvalToBe("[1, 2, 3]", "Ok([1, 2, 3])") - testEvalToBe("['hello', 'world']", "Ok(['hello', 'world'])") + testEvalToBe("[1, 2, 3]", "Ok([1,2,3])") + testEvalToBe("['hello', 'world']", "Ok(['hello','world'])") testEvalToBe("([0,1,2])[1]", "Ok(1)") 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})")) + test("define", () => expectEvalToBe("{a: 1, b: 2}", "Ok({a: 1,b: 2})")) test("index", () => expectEvalToBe("{a: 1}.a", "Ok(1)")) test("index not found", () => expectEvalToBe("{a: 1}.b", "Error(Record property not found: b)")) }) @@ -91,7 +84,7 @@ describe("eval", () => { 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)") + testEvalToBe("x=1; x=1", "Ok({x: 1})") }) }) diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res index 33afd311..1ff1c85e 100644 --- a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res +++ b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res @@ -119,27 +119,33 @@ describe("eval on distribution functions", () => { describe("parse on distribution functions", () => { describe("power", () => { - testParse("normal(5,2) ^ normal(5,1)", "Ok((:pow (:normal 5 2) (:normal 5 1)))") - testParse("3 ^ normal(5,1)", "Ok((:pow 3 (:normal 5 1)))") - testParse("normal(5,2) ^ 3", "Ok((:pow (:normal 5 2) 3))") + testParse("normal(5,2) ^ normal(5,1)", "Ok((:$$block (:pow (:normal 5 2) (:normal 5 1))))") + testParse("3 ^ normal(5,1)", "Ok((:$$block (:pow 3 (:normal 5 1))))") + testParse("normal(5,2) ^ 3", "Ok((:$$block (:pow (:normal 5 2) 3)))") }) describe("subtraction", () => { - testParse("10 - normal(5,1)", "Ok((:subtract 10 (:normal 5 1)))") - testParse("normal(5,1) - 10", "Ok((:subtract (:normal 5 1) 10))") + testParse("10 - normal(5,1)", "Ok((:$$block (:subtract 10 (:normal 5 1))))") + testParse("normal(5,1) - 10", "Ok((:$$block (:subtract (:normal 5 1) 10)))") }) 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)))", + "Ok((:$$block (:dotPow (: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)))") + testParse( + "normal(5,2) .* normal(5,1)", + "Ok((:$$block (:dotMultiply (:normal 5 2) (:normal 5 1))))", + ) + testParse( + "normal(5,2) ./ normal(5,1)", + "Ok((:$$block (:dotDivide (:normal 5 2) (:normal 5 1))))", + ) + testParse("normal(5,2) .^ normal(5,1)", "Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))") }) describe("equality", () => { - testParse("5 == normal(5,2)", "Ok((:equal 5 (:normal 5 2)))") + testParse("5 == normal(5,2)", "Ok((:$$block (:equal 5 (:normal 5 2))))") }) describe("pointwise adding two normals", () => { testParse(~skip=true, "normal(5,2) .+ normal(5,1)", "Ok((:dotAdd (:normal 5 2) (:normal 5 1)))") diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res index fc2d555e..888aca7e 100644 --- a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res +++ b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_ExpressionValue_test.res @@ -3,9 +3,9 @@ open Jest open Expect describe("ExpressionValue", () => { - test("argsToString", () => expect([EvNumber(1.), EvString("a")]->argsToString)->toBe("1, 'a'")) + test("argsToString", () => expect([EvNumber(1.), EvString("a")]->argsToString)->toBe("1,'a'")) test("toStringFunctionCall", () => - expect(("fn", [EvNumber(1.), EvString("a")])->toStringFunctionCall)->toBe("fn(1, 'a')") + expect(("fn", [EvNumber(1.), EvString("a")])->toStringFunctionCall)->toBe("fn(1,'a')") ) }) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res index a403ccd3..c9c9f41e 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res @@ -12,5 +12,3 @@ type externalBindings = ReducerInterface_ExpressionValue.externalBindings let evaluate = Expression.evaluate let evaluateUsingOptions = Expression.evaluateUsingOptions let parse = Expression.parse -let parseOuter = Expression.parseOuter -let parsePartial = Expression.parsePartial diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi index 8ea6047a..880dd1e7 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi @@ -18,12 +18,9 @@ type externalBindings = ReducerInterface_ExpressionValue.externalBindings let evaluateUsingOptions: ( ~environment: option, ~externalBindings: option, - ~isPartial: option, string, ) => result @genType let evaluate: string => result let parse: string => result -let parseOuter: string => result -let parsePartial: string => result 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 93960cf6..04bd1be4 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 @@ -1,5 +1,6 @@ module ExternalLibrary = ReducerInterface.ExternalLibrary module MathJs = Reducer_MathJs +module Bindings = Reducer_Expression_Bindings open ReducerInterface.ExpressionValue open Reducer_ErrorValue @@ -68,6 +69,20 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> => value->Ok } + let doSetBindings = ( + externalBindings: externalBindings, + symbol: string, + value: expressionValue, + ) => { + Bindings.fromExternalBindings(externalBindings) + ->Belt.Map.String.set(symbol, value) + ->Bindings.toExternalBindings + ->EvRecord + ->Ok + } + + let doExportBindings = (externalBindings: externalBindings) => EvRecord(externalBindings)->Ok + switch call { | ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) => arrayAtIndex(aValueArray, fIndex) @@ -78,6 +93,9 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> => | ("inspect", [value, EvString(label)]) => inspectLabel(value, label) | ("inspect", [value]) => inspect(value) | ("inspectPerformance", [value, EvString(label)]) => inspectPerformance(value, label) + | ("$setBindings", [EvRecord(externalBindings), EvSymbol(symbol), value]) => + doSetBindings(externalBindings, symbol, value) + | ("$exportBindings", [EvRecord(externalBindings)]) => doExportBindings(externalBindings) | call => callMathJs(call) } } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index 185897e9..951f444f 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -3,179 +3,143 @@ they take expressions as parameters and return a new expression. Macros are used to define language building blocks. They are like Lisp macros. */ +module Bindings = Reducer_Expression_Bindings module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface.ExpressionValue module Result = Belt.Result - -open Reducer_ErrorValue +open Reducer_Expression_ExpressionBuilder type expression = ExpressionT.expression type environment = ExpressionValue.environment - -type reducerFn = ( - expression, - ExpressionT.bindings, - environment, -) => result - -let rec replaceSymbols = (expression: expression, bindings: ExpressionT.bindings): result< - expression, - errorValue, -> => { - let getParameters = (bindings: ExpressionT.bindings): array => { - let eParameters = Belt.Map.String.getWithDefault(bindings, "$parameters", EParameters([])) - switch eParameters { - | EParameters(parameters) => parameters - | _ => [] - } - } - - let putParameters = ( - bindings: ExpressionT.bindings, - parameters: array, - ): ExpressionT.bindings => - Belt.Map.String.set(bindings, "$parameters", ExpressionT.EParameters(parameters)) - - let answerBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) => - switch Js.Array2.some(parameters, a => a == aSymbol) { - | true => defaultExpression->Ok // We cannot bind the parameters with global values - | false => - switch bindings->Belt.Map.String.get(aSymbol) { - | Some(boundExpression) => boundExpression->Ok - | None => RESymbolNotFound(aSymbol)->Error - } - } - - let answerCallBindingIfNotParameter = (aSymbol, defaultExpression, parameters, bindings) => - switch Js.Array2.some(parameters, a => a == aSymbol) { - | true => defaultExpression->Ok // We cannot bind the parameters with global values - | false => - switch bindings->Belt.Map.String.get(aSymbol) { - | Some(boundExpression) => boundExpression->Ok - | None => defaultExpression->Ok - } - } - - switch expression { - | ExpressionT.EValue(EvSymbol(aSymbol)) => { - let parameters = getParameters(bindings) - answerBindingIfNotParameter(aSymbol, expression, parameters, bindings) - } - | ExpressionT.EValue(EvCall(aSymbol)) => { - let parameters = getParameters(bindings) - answerCallBindingIfNotParameter(aSymbol, expression, parameters, bindings) - } - | ExpressionT.EValue(_) => expression->Ok - | ExpressionT.EBindings(_) => expression->Ok - | ExpressionT.EParameters(_) => expression->Ok - | ExpressionT.EList(list{ - ExpressionT.EValue(EvCall("$lambda")), - ExpressionT.EParameters(parameters), - expr, - }) => { - let oldParameters = getParameters(bindings) - let newParameters = oldParameters->Js.Array2.concat(parameters) - let newBindings = putParameters(bindings, newParameters) - let rNewExpr = replaceSymbols(expr, newBindings) - rNewExpr->Result.flatMap(newExpr => - ExpressionT.EList(list{ - ExpressionT.EValue(EvCall("$lambda")), - ExpressionT.EParameters(parameters), - newExpr, - })->Ok - ) - } - | ExpressionT.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 - }) - }) - ) - racc->Result.map(acc => acc->ExpressionT.EList) - } - } -} +type errorValue = Reducer_ErrorValue.errorValue let dispatchMacroCall = ( - list: list, + macroExpression: expression, bindings: ExpressionT.bindings, environment, - reduceExpression: reducerFn, -): result => { - let doBindStatement = (statement: expression, bindings: ExpressionT.bindings) => { + reduceExpression: ExpressionT.reducerFn, +): result => { + let doBindStatement = (bindingExpr: expression, statement: expression, environment) => switch statement { - | ExpressionT.EList(list{ - ExpressionT.EValue(EvCall("$let")), - ExpressionT.EValue(EvSymbol(aSymbol)), - expressionToReduce, - }) => { - let rNewExpressionToReduce = replaceSymbols(expressionToReduce, bindings) - - let rNewValue = - rNewExpressionToReduce->Result.flatMap(newExpressionToReduce => - reduceExpression(newExpressionToReduce, bindings, environment) - ) - - let rNewExpression = rNewValue->Result.map(newValue => ExpressionT.EValue(newValue)) - rNewExpression->Result.map(newExpression => - Belt.Map.String.set(bindings, aSymbol, newExpression)->ExpressionT.EBindings + | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { + let rExternalBindingsValue = reduceExpression( + bindingExpr, + Bindings.defaultBindings, + environment, ) + + rExternalBindingsValue->Result.flatMap(externalBindingsValue => { + let newBindings = Bindings.fromValue(externalBindingsValue) + let rNewStatement = Bindings.replaceSymbols(newBindings, statement) + rNewStatement->Result.map(newStatement => + eFunction( + "$setBindings", + list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement}, + ) + ) + }) } | _ => REAssignmentExpected->Error } - } - let doExportVariableExpression = (bindings: ExpressionT.bindings) => { - let emptyDictionary: Js.Dict.t = Js.Dict.empty() - let reducedBindings = bindings->Belt.Map.String.keep((_key, value) => - switch value { - | ExpressionT.EValue(_) => true - | _ => false - } - ) - let externalBindings = reducedBindings->Belt.Map.String.reduce(emptyDictionary, ( - acc, - key, - expressionValue, - ) => { - let value = switch expressionValue { - | ExpressionT.EValue(aValue) => aValue - | _ => EvSymbol("internal") - } - Js.Dict.set(acc, key, value) - acc - }) - externalBindings->ExpressionValue.EvRecord->ExpressionT.EValue->Ok - } + let doBindExpression = (bindingExpr: expression, statement: expression, environment) => + switch statement { + | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { + let rExternalBindingsValue = reduceExpression( + bindingExpr, + Bindings.defaultBindings, + environment, + ) - let doBindExpression = (expression: expression, bindings: ExpressionT.bindings) => - switch expression { - | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), ..._}) => - REExpressionExpected->Error - | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$exportVariablesExpression"))}) => - doExportVariableExpression(bindings) - | _ => replaceSymbols(expression, bindings) + rExternalBindingsValue->Result.flatMap(externalBindingsValue => { + let newBindings = Bindings.fromValue(externalBindingsValue) + let rNewStatement = Bindings.replaceSymbols(newBindings, statement) + rNewStatement->Result.map(newStatement => + eFunction( + "$exportBindings", + list{ + eFunction( + "$setBindings", + list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement}, + ), + }, + ) + ) + }) + } + | _ => { + let rExternalBindingsValue = reduceExpression( + bindingExpr, + Bindings.defaultBindings, + environment, + ) + rExternalBindingsValue->Result.flatMap(externalBindingsValue => { + let newBindings = Bindings.fromValue(externalBindingsValue) + let rNewStatement = Bindings.replaceSymbols(newBindings, statement) + rNewStatement + }) + } } - switch list { - | list{ExpressionT.EValue(EvCall("$$bindings"))} => bindings->ExpressionT.EBindings->Ok + let doBlock = (exprs: list, _bindings: ExpressionT.bindings, _environment): result< + expression, + errorValue, + > => { + let exprsArray = Belt.List.toArray(exprs) + let maxIndex = Js.Array2.length(exprsArray) - 1 + exprsArray->Js.Array2.reducei((acc, statement, index) => + if index == 0 { + if index == maxIndex { + eBindExpressionDefault(statement) + } else { + eBindStatementDefault(statement) + } + } else if index == maxIndex { + eBindExpression(acc, statement) + } else { + eBindStatement(acc, statement) + } + , eSymbol("undefined block"))->Ok + } - | list{ - ExpressionT.EValue(EvCall("$$bindStatement")), - ExpressionT.EBindings(bindings), - statement, - } => - doBindStatement(statement, bindings) - | list{ - ExpressionT.EValue(EvCall("$$bindExpression")), - ExpressionT.EBindings(bindings), - expression, - } => - doBindExpression(expression, bindings) - | _ => list->ExpressionT.EList->Ok + let doLambdaDefinition = ( + bindings: ExpressionT.bindings, + parameters: array, + lambdaDefinition: ExpressionT.expression, + ) => eLambda(parameters, bindings->Bindings.toExternalBindings, lambdaDefinition)->Ok + + let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment) => + switch aList { + | list{ + ExpressionT.EValue(EvCall("$$bindStatement")), + bindingExpr: ExpressionT.expression, + statement, + } => + doBindStatement(bindingExpr, statement, environment) + | list{ExpressionT.EValue(EvCall("$$bindStatement")), statement} => + // bindings of the context are used when there is no binding expression + doBindStatement(eRecord(Bindings.toExternalBindings(bindings)), statement, environment) + | list{ + ExpressionT.EValue(EvCall("$$bindExpression")), + bindingExpr: ExpressionT.expression, + expression, + } => + doBindExpression(bindingExpr, expression, environment) + | list{ExpressionT.EValue(EvCall("$$bindExpression")), expression} => + // bindings of the context are used when there is no binding expression + doBindExpression(eRecord(Bindings.toExternalBindings(bindings)), expression, environment) + | list{ExpressionT.EValue(EvCall("$$block")), ...exprs} => doBlock(exprs, bindings, environment) + | list{ + ExpressionT.EValue(EvCall("$$lambda")), + ExpressionT.EValue(EvArrayString(parameters)), + lambdaDefinition, + } => + doLambdaDefinition(bindings, parameters, lambdaDefinition) + | _ => ExpressionT.EList(aList)->Ok + } + + switch macroExpression { + | EList(aList) => expandExpressionList(aList, bindings, environment) + | _ => macroExpression->Ok } } 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 1713476f..e69c27d8 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 @@ -1,13 +1,14 @@ -module Builder = Reducer_Expression_Builder +module Bindings = Reducer_Expression_Bindings module BuiltIn = Reducer_Dispatch_BuiltIn +module ExpressionBuilder = Reducer_Expression_ExpressionBuilder module ExpressionValue = ReducerInterface.ExpressionValue module Extra = Reducer_Extra +module Lambda = Reducer_Expression_Lambda +module Macro = Reducer_Expression_Macro module MathJs = Reducer_MathJs module Result = Belt.Result module T = Reducer_Expression_T -open Reducer_ErrorValue - type environment = ReducerInterface_ExpressionValue.environment type errorValue = Reducer_ErrorValue.errorValue type expression = T.expression @@ -16,30 +17,6 @@ type externalBindings = ReducerInterface_ExpressionValue.externalBindings type internalCode = ReducerInterface_ExpressionValue.internalCode type t = expression -external castExpressionToInternalCode: expression => internalCode = "%identity" -external castInternalCodeToExpression: internalCode => expression = "%identity" - -/* - Shows the expression as text of expression -*/ -let rec toString = expression => - switch expression { - | T.EBindings(_) => "$$bound" - | T.EParameters(params) => `(${Js.Array2.toString(params)})` - | T.EList(aList) => - `(${Belt.List.map(aList, aValue => toString(aValue)) - ->Extra.List.interperse(" ") - ->Belt.List.toArray - ->Js.String.concatMany("")})` - | EValue(aValue) => ExpressionValue.toString(aValue) - } - -let toStringResult = codeResult => - switch codeResult { - | Ok(a) => `Ok(${toString(a)})` - | Error(m) => `Error(${Js.String.make(m)})` - } - /* Converts a MathJs code to expression */ @@ -49,14 +26,6 @@ let parse_ = (expr: string, parser, converter): result => let parse = (mathJsCode: string): result => mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromNode) -let parsePartial = (mathJsCode: string): result => - mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromPartialNode) - -let parseOuter = (mathJsCode: string): result => - mathJsCode->parse_(MathJs.Parse.parse, MathJs.ToExpression.fromOuterNode) - -let defaultBindings: T.bindings = Belt.Map.String.empty - /* Recursively evaluate/reduce the expression (Lisp AST) */ @@ -64,144 +33,63 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en expressionValue, 'e, > => { - /* - 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, environment: environment): result< - t, - 'e, - > => - Reducer_Dispatch_BuiltInMacros.dispatchMacroCall(list, bindings, environment, reduceExpression) - - let applyParametersToLambda = ( - internal: internalCode, - parameters: array, - args: list, - environment, - ): result => { - let expr = castInternalCodeToExpression(internal) - let parameterList = parameters->Belt.List.fromArray - let zippedParameterList = parameterList->Belt.List.zip(args) - let bindings = Belt.List.reduce(zippedParameterList, defaultBindings, (a, (p, e)) => - a->Belt.Map.String.set(p, e->T.EValue) - ) - let newExpression = Builder.passToFunction( - "$$bindExpression", - list{Builder.passToFunction("$$bindings", list{}), expr}, - ) - reduceExpression(newExpression, bindings, environment) + switch expression { + | T.EValue(value) => value->Ok + | T.EList(list) => + switch list { + | list{EValue(EvCall(fName)), ..._args} => + switch Macro.isMacroName(fName) { + // A macro expands then reduces itself + | true => Macro.doMacroCall(expression, bindings, environment, reduceExpression) + | false => reduceExpressionList(list, bindings, environment) + } + | _ => reduceExpressionList(list, bindings, environment) + } } - - /* - After reducing each level of expression(Lisp AST), we have a value list to evaluate - */ - let reduceValueList = (valueList: list, environment): result< - expressionValue, - 'e, - > => - switch valueList { - | list{EvCall(fName), ...args} => - (fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment) - // "(lambda(x=>internal) param)" - | list{EvLambda((parameters, internal)), ...args} => - applyParametersToLambda(internal, parameters, args, environment) - | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok - } - - let rec seekMacros = (expression: t, bindings: T.bindings, environment): result => - switch expression { - | T.EValue(_value) => expression->Ok - | T.EBindings(_value) => expression->Ok - | T.EParameters(_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, environment) - ->Result.flatMap(newNode => { - acc->Belt.List.add(newNode)->Ok - }) - }) - ) - racc->Result.flatMap(acc => acc->doMacroCall(bindings, environment)) - } - } - - let rec reduceExpandedExpression = (expression: t, environment): result => - switch expression { - | T.EList(list{T.EValue(EvCall("$lambda")), T.EParameters(parameters), functionDefinition}) => - EvLambda((parameters, functionDefinition->castExpressionToInternalCode))->Ok - | 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(environment) - ->Result.flatMap(newNode => { - acc->Belt.List.add(newNode)->Ok - }) - }) - ) - racc->Result.flatMap(acc => acc->reduceValueList(environment)) - } - | EBindings(_bindings) => RETodo("Error: Bindings cannot be reduced to values")->Error - | EParameters(_parameters) => - RETodo("Error: Lambda Parameters cannot be reduced to values")->Error - } - - let rExpandedExpression: result = expression->seekMacros(bindings, environment) - rExpandedExpression->Result.flatMap(expandedExpression => - expandedExpression->reduceExpandedExpression(environment) +} +and reduceExpressionList = ( + expressions: list, + bindings: T.bindings, + environment: environment, +): result => { + let racc: result, 'e> = expressions->Belt.List.reduceReverse(Ok(list{}), ( + racc, + each: expression, + ) => + racc->Result.flatMap(acc => { + each + ->reduceExpression(bindings, environment) + ->Result.map(newNode => { + acc->Belt.List.add(newNode) + }) + }) ) + racc->Result.flatMap(acc => acc->reduceValueList(environment)) } -let evalUsingExternalBindingsExpression_ = (aExpression, bindings, environment): result< +/* + After reducing each level of expression(Lisp AST), we have a value list to evaluate + */ +and reduceValueList = (valueList: list, environment): result< + expressionValue, + 'e, +> => + switch valueList { + | list{EvCall(fName), ...args} => (fName, args->Belt.List.toArray)->BuiltIn.dispatch(environment) + + | list{EvLambda(lamdaCall), ...args} => + Lambda.doLambdaCall(lamdaCall, args, environment, reduceExpression) + | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok + } + +let evalUsingBindingsExpression_ = (aExpression, bindings, environment): result< expressionValue, 'e, > => reduceExpression(aExpression, bindings, environment) -/* - Evaluates MathJs code via Reducer using bindings and answers the result. - When bindings are used, the code is a partial code as if it is cut from a larger code. - Therefore all statements are assignments. -*/ -let evalPartial_ = (codeText: string, bindings: T.bindings, environment: environment) => { - parsePartial(codeText)->Result.flatMap(expression => - expression->evalUsingExternalBindingsExpression_(bindings, environment) - ) -} - -/* - Evaluates MathJs code via Reducer using bindings and answers the result. - When bindings are used, the code is a partial code as if it is cut from a larger code. - Therefore all statments are assignments. -*/ -let evalOuter_ = (codeText: string, bindings: T.bindings, environment: environment) => { - parseOuter(codeText)->Result.flatMap(expression => - expression->evalUsingExternalBindingsExpression_(bindings, environment) - ) -} - -let externalBindingsToBindings = (externalBindings: externalBindings): T.bindings => { - let keys = Js.Dict.keys(externalBindings) - keys->Belt.Array.reduce(defaultBindings, (acc, key) => { - let value = Js.Dict.unsafeGet(externalBindings, key) - acc->Belt.Map.String.set(key, T.EValue(value)) - }) -} - let evaluateUsingOptions = ( ~environment: option, ~externalBindings: option, - ~isPartial: option, code: string, ): result => { let anEnvironment = switch environment { @@ -214,24 +102,15 @@ let evaluateUsingOptions = ( | None => ReducerInterface_ExpressionValue.defaultExternalBindings } - let anIsPartial = switch isPartial { - | Some(isPartial) => isPartial - | None => false - } + let bindings = anExternalBindings->Bindings.fromExternalBindings - let bindings = anExternalBindings->externalBindingsToBindings - - if anIsPartial { - evalPartial_(code, bindings, anEnvironment) - } else { - evalOuter_(code, bindings, anEnvironment) - } + parse(code)->Result.flatMap(expr => evalUsingBindingsExpression_(expr, bindings, anEnvironment)) } /* Evaluates MathJs code and bindings via Reducer and answers the result */ let evaluate = (code: string): result => { - evaluateUsingOptions(~environment=None, ~externalBindings=None, ~isPartial=None, code) + evaluateUsingOptions(~environment=None, ~externalBindings=None, code) } let eval = evaluate diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res new file mode 100644 index 00000000..add7f614 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res @@ -0,0 +1,73 @@ +module ExpressionT = Reducer_Expression_T +module ExpressionValue = ReducerInterface.ExpressionValue +module Result = Belt.Result + +type errorValue = Reducer_ErrorValue.errorValue +type expression = ExpressionT.expression +type expressionValue = ExpressionValue.expressionValue +type externalBindings = ReducerInterface_ExpressionValue.externalBindings + +let defaultBindings: ExpressionT.bindings = Belt.Map.String.empty + +let fromExternalBindings = (externalBindings: externalBindings): ExpressionT.bindings => { + let keys = Js.Dict.keys(externalBindings) + keys->Belt.Array.reduce(defaultBindings, (acc, key) => { + let value = Js.Dict.unsafeGet(externalBindings, key) + acc->Belt.Map.String.set(key, value) + }) +} + +let toExternalBindings = (bindings: ExpressionT.bindings): externalBindings => { + let keys = Belt.Map.String.keysToArray(bindings) + keys->Belt.Array.reduce(Js.Dict.empty(), (acc, key) => { + let value = bindings->Belt.Map.String.getExn(key) + Js.Dict.set(acc, key, value) + acc + }) +} + +let fromValue = (aValue: expressionValue) => + switch aValue { + | EvRecord(externalBindings) => fromExternalBindings(externalBindings) + | _ => defaultBindings + } + +let externalFromArray = anArray => Js.Dict.fromArray(anArray) + +let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$") + +let rec replaceSymbols = (bindings: ExpressionT.bindings, expression: expression): result< + expression, + errorValue, +> => + switch expression { + | ExpressionT.EValue(value) => + replaceSymbolOnValue(bindings, value)->Result.map(evValue => evValue->ExpressionT.EValue) + | ExpressionT.EList(list) => + switch list { + | list{EValue(EvCall(fName)), ..._args} => + switch isMacroName(fName) { + // A macro reduces itself so we dont dive in it + | true => expression->Ok + | false => replaceSymbolsOnExpressionList(bindings, list) + } + | _ => replaceSymbolsOnExpressionList(bindings, list) + } + } + +and replaceSymbolsOnExpressionList = (bindings, list) => { + let racc = list->Belt.List.reduceReverse(Ok(list{}), (racc, each: expression) => + racc->Result.flatMap(acc => { + replaceSymbols(bindings, each)->Result.flatMap(newNode => { + acc->Belt.List.add(newNode)->Ok + }) + }) + ) + racc->Result.map(acc => acc->ExpressionT.EList) +} +and replaceSymbolOnValue = (bindings, evValue: expressionValue) => + switch evValue { + | EvSymbol(symbol) | EvCall(symbol) => + Belt.Map.String.getWithDefault(bindings, symbol, evValue)->Ok + | _ => evValue->Ok + } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res deleted file mode 100644 index 4e5a988e..00000000 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Builder.res +++ /dev/null @@ -1,16 +0,0 @@ -module ErrorValue = Reducer_ErrorValue -module ExpressionT = Reducer_Expression_T -module ExpressionValue = ReducerInterface.ExpressionValue -module Result = Belt.Result - -type errorValue = ErrorValue.errorValue -type expression = ExpressionT.expression - -let passToFunction = (fName: string, lispArgs: list): expression => { - let toEvCallValue = (name: string): expression => name->ExpressionValue.EvCall->ExpressionT.EValue - let fn = fName->toEvCallValue - list{fn, ...lispArgs}->ExpressionT.EList -} - -let toEvSymbolValue = (name: string): expression => - name->ExpressionValue.EvSymbol->ExpressionT.EValue diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res new file mode 100644 index 00000000..ec3a0214 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res @@ -0,0 +1,60 @@ +module BBindings = Reducer_Expression_Bindings +module BErrorValue = Reducer_ErrorValue +module BExpressionT = Reducer_Expression_T +module BExpressionValue = ReducerInterface.ExpressionValue + +type errorValue = BErrorValue.errorValue +type expression = BExpressionT.expression +type internalCode = ReducerInterface_ExpressionValue.internalCode + +external castExpressionToInternalCode: expression => internalCode = "%identity" + +let eArray = anArray => anArray->BExpressionValue.EvArray->BExpressionT.EValue + +let eArrayString = anArray => anArray->BExpressionValue.EvArrayString->BExpressionT.EValue + +let eBindings = (anArray: array<(string, BExpressionValue.expressionValue)>) => + anArray->Js.Dict.fromArray->EvRecord->BExpressionT.EValue + +let eBool = aBool => aBool->BExpressionValue.EvBool->BExpressionT.EValue + +let eCall = (name: string): expression => name->BExpressionValue.EvCall->BExpressionT.EValue + +let eFunction = (fName: string, lispArgs: list): expression => { + let fn = fName->eCall + list{fn, ...lispArgs}->BExpressionT.EList +} + +let eLambda = (parameters: array, context, expr) => + BExpressionValue.EvLambda( + parameters, + context, + expr->castExpressionToInternalCode, + )->BExpressionT.EValue + +let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue + +let eRecord = aRecord => aRecord->BExpressionValue.EvRecord->BExpressionT.EValue + +let eString = aString => aString->BExpressionValue.EvString->BExpressionT.EValue + +let eSymbol = (name: string): expression => name->BExpressionValue.EvSymbol->BExpressionT.EValue + +let eList = (list: list): expression => list->BExpressionT.EList + +let eBlock = (exprs: list): expression => eFunction("$$block", exprs) + +let eLetStatement = (symbol: string, valueExpression: expression): expression => + eFunction("$let", list{eSymbol(symbol), valueExpression}) + +let eBindStatement = (bindingExpr: expression, letStatement: expression): expression => + eFunction("$$bindStatement", list{bindingExpr, letStatement}) + +let eBindStatementDefault = (letStatement: expression): expression => + eFunction("$$bindStatement", list{letStatement}) + +let eBindExpression = (bindingExpr: expression, expression: expression): expression => + eFunction("$$bindExpression", list{bindingExpr, expression}) + +let eBindExpressionDefault = (expression: expression): expression => + eFunction("$$bindExpression", list{expression}) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res new file mode 100644 index 00000000..a2d795c0 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res @@ -0,0 +1,35 @@ +module Bindings = Reducer_Expression_Bindings +module ExpressionBuilder = Reducer_Expression_ExpressionBuilder +module ExpressionT = Reducer_Expression_T +module ExpressionValue = ReducerInterface.ExpressionValue + +type environment = ReducerInterface_ExpressionValue.environment +type expression = ExpressionT.expression +type expressionValue = ReducerInterface_ExpressionValue.expressionValue +type externalBindings = ReducerInterface_ExpressionValue.externalBindings +type internalCode = ReducerInterface_ExpressionValue.internalCode + +external castInternalCodeToExpression: internalCode => expression = "%identity" + +let applyParametersToLambda = ( + internal: internalCode, + parameters: array, + args: list, + context: externalBindings, + environment, + reducer: ExpressionT.reducerFn, +): result => { + let expr = castInternalCodeToExpression(internal) + let parameterList = parameters->Belt.List.fromArray + let zippedParameterList = parameterList->Belt.List.zip(args) + let bindings = Belt.List.reduce(zippedParameterList, context->Bindings.fromExternalBindings, ( + acc, + (variable, variableValue), + ) => acc->Belt.Map.String.set(variable, variableValue)) + let newExpression = ExpressionBuilder.eBlock(list{expr}) + reducer(newExpression, bindings, environment) +} + +let doLambdaCall = ((parameters, context, internal), args, environment, reducer) => { + applyParametersToLambda(internal, parameters, args, context, environment, reducer) +} diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res new file mode 100644 index 00000000..5ac19502 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res @@ -0,0 +1,35 @@ +module ExpressionT = Reducer_Expression_T +module ExpressionValue = ReducerInterface.ExpressionValue +module Result = Belt.Result + +type environment = ExpressionValue.environment +type expression = ExpressionT.expression +type expressionValue = ExpressionValue.expressionValue + +let expandMacroCall = ( + macroExpression: expression, + bindings: ExpressionT.bindings, + environment: environment, + reduceExpression: ExpressionT.reducerFn, +): result => + Reducer_Dispatch_BuiltInMacros.dispatchMacroCall( + macroExpression, + bindings, + environment, + reduceExpression, + ) + +let doMacroCall = ( + macroExpression: expression, + bindings: ExpressionT.bindings, + environment: environment, + reduceExpression: ExpressionT.reducerFn, +): result => + expandMacroCall( + macroExpression, + bindings, + environment, + reduceExpression, + )->Result.flatMap(expression => reduceExpression(expression, bindings, environment)) + +let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$") 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 c3fd822c..b21ba8b7 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,3 @@ -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 @@ -8,9 +6,51 @@ open ReducerInterface.ExpressionValue 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. */ +module Extra = Reducer_Extra +module ExpressionValue = ReducerInterface.ExpressionValue + +type expressionValue = ExpressionValue.expressionValue +type environment = ExpressionValue.environment + 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 kind of statements return bindings; for internal use only - | EParameters(array) // for $defun; for internal use only -and bindings = Belt.Map.String.t +and bindings = Belt.Map.String.t + +type reducerFn = ( + expression, + bindings, + environment, +) => result + +/* + Converts the expression to String +*/ +let rec toString = expression => + switch expression { + | EList(aList) => + `(${Belt.List.map(aList, aValue => toString(aValue)) + ->Extra.List.interperse(" ") + ->Belt.List.toArray + ->Js.String.concatMany("")})` + | EValue(aValue) => ExpressionValue.toString(aValue) + } + +let toStringResult = codeResult => + switch codeResult { + | Ok(a) => `Ok(${toString(a)})` + | Error(m) => `Error(${Reducer_ErrorValue.errorToString(m)})` + } + +let inspect = (expr: expression): expression => { + Js.log(toString(expr)) + expr +} + +let inspectResult = (r: result): result< + expression, + Reducer_ErrorValue.errorValue, +> => { + Js.log(toStringResult(r)) + r +} 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 5dc53413..ca040190 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,37 +1,34 @@ -module Builder = Reducer_Expression_Builder +/* * WARNING. DO NOT EDIT, BEAUTIFY, COMMENT ON OR REFACTOR THIS CODE. +We will stop using MathJs parser and +this whole file will go to trash +**/ module ErrorValue = Reducer_ErrorValue +module ExpressionBuilder = Reducer_Expression_ExpressionBuilder module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface.ExpressionValue module JavaScript = Reducer_Js module Parse = Reducer_MathJs_Parse module Result = Belt.Result +type errorValue = ErrorValue.errorValue type expression = ExpressionT.expression type expressionValue = ExpressionValue.expressionValue -type errorValue = ErrorValue.errorValue -type blockTag = - | ImportVariablesStatement - | ExportVariablesExpression -type tagOrNode = - | BlockTag(blockTag) - | BlockNode(Parse.node) +let blockToNode = block => block["node"] -let toTagOrNode = block => BlockNode(block["node"]) - -let rec fromNode = (mathJsNode: Parse.node): result => +let rec fromInnerNode = (mathJsNode: Parse.node): result => Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => { let fromNodeList = (nodeList: list): result, 'e> => Belt.List.reduceReverse(nodeList, Ok(list{}), (racc, currNode) => racc->Result.flatMap(acc => - fromNode(currNode)->Result.map(currCode => list{currCode, ...acc}) + fromInnerNode(currNode)->Result.map(currCode => list{currCode, ...acc}) ) ) let caseFunctionNode = fNode => { let rLispArgs = fNode["args"]->Belt.List.fromArray->fromNodeList - rLispArgs->Result.flatMap(lispArgs => - Builder.passToFunction(fNode->Parse.nameOfFunctionNode, lispArgs)->Ok + rLispArgs->Result.map(lispArgs => + ExpressionBuilder.eFunction(fNode->Parse.nameOfFunctionNode, lispArgs) ) } @@ -42,18 +39,15 @@ let rec fromNode = (mathJsNode: Parse.node): result => (key: string, value: Parse.node), ) => racc->Result.flatMap(acc => - fromNode(value)->Result.map(valueExpression => { + fromInnerNode(value)->Result.map(valueExpression => { let entryCode = - list{ - key->ExpressionValue.EvString->ExpressionT.EValue, - valueExpression, - }->ExpressionT.EList + list{ExpressionBuilder.eString(key), valueExpression}->ExpressionT.EList list{entryCode, ...acc} }) ) ) rargs->Result.flatMap(args => - Builder.passToFunction("$constructRecord", list{ExpressionT.EList(args)})->Ok + ExpressionBuilder.eFunction("$constructRecord", list{ExpressionT.EList(args)})->Ok ) // $constructRecord gets a single argument: List of key-value paiers } @@ -66,7 +60,7 @@ let rec fromNode = (mathJsNode: Parse.node): result => Ok(list{}), (racc, currentPropertyMathJsNode) => racc->Result.flatMap(acc => - fromNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{ + fromInnerNode(currentPropertyMathJsNode)->Result.map(propertyCode => list{ propertyCode, ...acc, }) @@ -77,28 +71,41 @@ let rec fromNode = (mathJsNode: Parse.node): result => let caseAccessorNode = (objectNode, indexNode) => { caseIndexNode(indexNode)->Result.flatMap(indexCode => { - fromNode(objectNode)->Result.flatMap(objectCode => - Builder.passToFunction("$atIndex", list{objectCode, indexCode})->Ok + fromInnerNode(objectNode)->Result.flatMap(objectCode => + ExpressionBuilder.eFunction("$atIndex", list{objectCode, indexCode})->Ok ) }) } + let caseBlock = (nodesArray: array): result => { + let rStatements: result, 'a> = + nodesArray + ->Belt.List.fromArray + ->Belt.List.reduceReverse(Ok(list{}), (racc, currNode) => + racc->Result.flatMap(acc => + fromInnerNode(currNode)->Result.map(currCode => list{currCode, ...acc}) + ) + ) + rStatements->Result.map(statements => ExpressionBuilder.eBlock(statements)) + } + let caseAssignmentNode = aNode => { - let symbol = aNode["object"]["name"]->Builder.toEvSymbolValue - let rValueExpression = fromNode(aNode["value"]) - rValueExpression->Result.flatMap(valueExpression => - Builder.passToFunction("$let", list{symbol, valueExpression})->Ok + let symbolName = aNode["object"]["name"] + let rValueExpression = fromInnerNode(aNode["value"]) + rValueExpression->Result.map(valueExpression => + ExpressionBuilder.eLetStatement(symbolName, valueExpression) ) } let caseFunctionAssignmentNode = faNode => { - let symbol = faNode["name"]->Builder.toEvSymbolValue - let rValueExpression = fromNode(faNode["expr"]) + let symbol = faNode["name"]->ExpressionBuilder.eSymbol + let rValueExpression = fromInnerNode(faNode["expr"]) rValueExpression->Result.flatMap(valueExpression => { - let lispParams = faNode["params"]->ExpressionT.EParameters - let lambda = Builder.passToFunction("$lambda", list{lispParams, valueExpression}) - Builder.passToFunction("$let", list{symbol, lambda})->Ok + let lispParams = ExpressionBuilder.eArrayString(faNode["params"]) + let valueBlock = ExpressionBuilder.eBlock(list{valueExpression}) + let lambda = ExpressionBuilder.eFunction("$$lambda", list{lispParams, valueBlock}) + ExpressionBuilder.eFunction("$let", list{symbol, lambda})->Ok }) } @@ -111,11 +118,11 @@ let rec fromNode = (mathJsNode: Parse.node): result => | MjArrayNode(aNode) => caseArrayNode(aNode) | MjAssignmentNode(aNode) => caseAssignmentNode(aNode) | MjSymbolNode(sNode) => { - let expr: expression = Builder.toEvSymbolValue(sNode["name"]) + let expr: expression = ExpressionBuilder.eSymbol(sNode["name"]) let rExpr: result = expr->Ok rExpr } - | MjBlockNode(bNode) => bNode["blocks"]->Belt.Array.map(toTagOrNode)->caseTagOrNodes + | MjBlockNode(bNode) => bNode["blocks"]->Js.Array2.map(blockToNode)->caseBlock | MjConstantNode(cNode) => cNode["value"]->JavaScript.Gate.jsToEv->Result.flatMap(v => v->ExpressionT.EValue->Ok) | MjFunctionAssignmentNode(faNode) => caseFunctionAssignmentNode(faNode) @@ -123,78 +130,10 @@ let rec fromNode = (mathJsNode: Parse.node): result => | MjIndexNode(iNode) => caseIndexNode(iNode) | MjObjectNode(oNode) => caseObjectNode(oNode) | MjOperatorNode(opNode) => opNode->Parse.castOperatorNodeToFunctionNode->caseFunctionNode - | MjParenthesisNode(pNode) => pNode["content"]->fromNode + | MjParenthesisNode(pNode) => pNode["content"]->fromInnerNode } rFinalExpression }) -and caseTagOrNodes = (tagOrNodes): result => { - let initialBindings = Builder.passToFunction("$$bindings", list{})->Ok - let lastIndex = Belt.Array.length(tagOrNodes) - 1 - tagOrNodes->Belt.Array.reduceWithIndex(initialBindings, (rPreviousBindings, tagOrNode, i) => { - rPreviousBindings->Result.flatMap(previousBindings => { - let rStatement: result = switch tagOrNode { - | BlockNode(node) => fromNode(node) - | BlockTag(tag) => - switch tag { - | ImportVariablesStatement => - Builder.passToFunction("$importVariablesStatement", list{})->Ok - | ExportVariablesExpression => - Builder.passToFunction("$exportVariablesExpression", list{})->Ok - } - } - let bindName = if i == lastIndex { - "$$bindExpression" - } else { - "$$bindStatement" - } - - rStatement->Result.flatMap((statement: expression) => { - Builder.passToFunction(bindName, list{previousBindings, statement})->Ok - }) - }) - }) -} - -let fromPartialNode = (mathJsNode: Parse.node): result => { - Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => { - let casePartialBlockNode = (bNode: Parse.blockNode) => { - let blocksOrTags = bNode["blocks"]->Belt.Array.map(toTagOrNode) - let completed = Js.Array2.concat(blocksOrTags, [BlockTag(ExportVariablesExpression)]) - completed->caseTagOrNodes - } - - let casePartialExpression = (node: Parse.node) => { - let completed = [BlockNode(node), BlockTag(ExportVariablesExpression)] - - completed->caseTagOrNodes - } - - let rFinalExpression: result = switch typedMathJsNode { - | MjBlockNode(bNode) => casePartialBlockNode(bNode) - | _ => casePartialExpression(mathJsNode) - } - rFinalExpression - }) -} - -let fromOuterNode = (mathJsNode: Parse.node): result => { - Parse.castNodeType(mathJsNode)->Result.flatMap(typedMathJsNode => { - let casePartialBlockNode = (bNode: Parse.blockNode) => { - let blocksOrTags = bNode["blocks"]->Belt.Array.map(toTagOrNode) - let completed = blocksOrTags - completed->caseTagOrNodes - } - - let casePartialExpression = (node: Parse.node) => { - let completed = [BlockNode(node)] - completed->caseTagOrNodes - } - - let rFinalExpression: result = switch typedMathJsNode { - | MjBlockNode(bNode) => casePartialBlockNode(bNode) - | _ => casePartialExpression(mathJsNode) - } - rFinalExpression - }) -} +let fromNode = (node: Parse.node): result => + fromInnerNode(node)->Result.map(expr => ExpressionBuilder.eBlock(list{expr})) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 7e8d1150..31168425 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -11,17 +11,19 @@ type internalCode = Object @genType type rec expressionValue = | EvArray(array) + | EvArrayString(array) | EvBool(bool) | EvCall(string) // External function call | EvDistribution(DistributionTypes.genericDist) - | EvLambda((array, internalCode)) + | EvLambda((array, record, internalCode)) | EvNumber(float) - | EvRecord(Js.Dict.t) + | EvRecord(record) | EvString(string) | EvSymbol(string) +and record = Js.Dict.t @genType -type externalBindings = Js.Dict.t +type externalBindings = record @genType let defaultExternalBindings: externalBindings = Js.Dict.empty() @@ -29,20 +31,21 @@ type functionCall = (string, array) let rec toString = aValue => switch aValue { + | EvArray(anArray) => { + let args = anArray->Js.Array2.map(each => toString(each))->Js.Array2.toString + `[${args}]` + } + | EvArrayString(anArray) => { + let args = anArray->Js.Array2.toString + `[${args}]` + } | EvBool(aBool) => Js.String.make(aBool) | EvCall(fName) => `:${fName}` - | EvLambda((parameters, _internalCode)) => `lambda(${Js.Array2.toString(parameters)}=>internal)` + | EvLambda((parameters, _context, _internalCode)) => + `lambda(${Js.Array2.toString(parameters)}=>internal)` | EvNumber(aNumber) => Js.String.make(aNumber) | EvString(aString) => `'${aString}'` | EvSymbol(aString) => `:${aString}` - | EvArray(anArray) => { - let args = - anArray - ->Belt.Array.map(each => toString(each)) - ->Extra_Array.interperse(", ") - ->Js.String.concatMany("") - `[${args}]` - } | EvRecord(aRecord) => aRecord->toStringRecord | EvDistribution(dist) => GenericDist.toString(dist) } @@ -50,19 +53,19 @@ and toStringRecord = aRecord => { let pairs = aRecord ->Js.Dict.entries - ->Belt.Array.map(((eachKey, eachValue)) => `${eachKey}: ${toString(eachValue)}`) - ->Extra_Array.interperse(", ") - ->Js.String.concatMany("") + ->Js.Array2.map(((eachKey, eachValue)) => `${eachKey}: ${toString(eachValue)}`) + ->Js.Array2.toString `{${pairs}}` } let toStringWithType = aValue => switch aValue { | EvArray(_) => `Array::${toString(aValue)}` + | EvArrayString(_) => `ArrayString::${toString(aValue)}` | EvBool(_) => `Bool::${toString(aValue)}` | EvCall(_) => `Call::${toString(aValue)}` | EvDistribution(_) => `Distribution::${toString(aValue)}` - | EvLambda((_parameters, _internalCode)) => `Lambda::${toString(aValue)}` + | EvLambda((_parameters, _context, _internalCode)) => `Lambda::${toString(aValue)}` | EvNumber(_) => `Number::${toString(aValue)}` | EvRecord(_) => `Record::${toString(aValue)}` | EvString(_) => `String::${toString(aValue)}` @@ -70,7 +73,7 @@ let toStringWithType = aValue => } let argsToString = (args: array): string => { - args->Belt.Array.map(arg => arg->toString)->Extra_Array.interperse(", ")->Js.String.concatMany("") + args->Js.Array2.map(arg => arg->toString)->Js.Array2.toString } let toStringFunctionCall = ((fn, args)): string => `${fn}(${argsToString(args)})` From 351381339c443155d824b68f5ae88a49f2e7bdd8 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Fri, 29 Apr 2022 18:14:02 +0200 Subject: [PATCH 27/53] bug fixed logs removed --- .../Reducer_Dispatch_BuiltInMacros_test.res | 21 ++++++++++++++++++ .../Reducer/Reducer_externalBindings_test.res | 2 ++ .../Reducer_Dispatch_BuiltIn.res | 4 ++-- .../Reducer_Dispatch_BuiltInMacros.res | 22 +++++++------------ .../Reducer_Expression/Reducer_Expression.res | 4 ++-- .../Reducer/Reducer_Js/Reducer_Js_Gate.res | 4 ++-- .../ReducerInterface_GenericDistribution.res | 8 +++---- 7 files changed, 41 insertions(+), 24 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res index ecf97697..eb6e6c0d 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res @@ -99,6 +99,27 @@ describe("block", () => { ) // Empty block testMacro([], eBlock(list{}), "Ok(:undefined block)") //TODO: should be an error + // :$$block (:$$block (:$let :y (:add :x 1)) :y)" + testMacro( + [], + eBlock(list{ + eBlock(list{ + eLetStatement("y", eFunction("add", list{eSymbol("x"), eNumber(1.)})), + eSymbol("y"), + }), + }), + "Ok((:$$bindExpression (:$$block (:$let :y (:add :x 1)) :y)))", + ) + MyOnly.testMacroEval( + [("x", EvNumber(1.))], + eBlock(list{ + eBlock(list{ + eLetStatement("y", eFunction("add", list{eSymbol("x"), eNumber(1.)})), + eSymbol("y"), + }), + }), + "Ok(2)", + ) }) describe("lambda", () => { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res index 4c2546f4..3a903343 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_externalBindings_test.res @@ -33,7 +33,9 @@ open Reducer_TestHelpers describe("Eval with Bindings", () => { testEvalBindingsToBe("x", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(1)") testEvalBindingsToBe("x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)") + testParseToBe("y = x+1; y", "Ok((:$$block (:$$block (:$let :y (:add :x 1)) :y)))") testEvalBindingsToBe("y = x+1; y", list{("x", ExpressionValue.EvNumber(1.))}, "Ok(2)") + testEvalBindingsToBe("y = x+1", list{("x", ExpressionValue.EvNumber(1.))}, "Ok({x: 1,y: 2})") }) /* 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 04bd1be4..0067441c 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 @@ -21,12 +21,12 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> => } let constructRecord = arrayOfPairs => { - Belt.Array.map(arrayOfPairs, pairValue => { + Belt.Array.map(arrayOfPairs, pairValue => switch pairValue { | EvArray([EvString(key), valueValue]) => (key, valueValue) | _ => ("wrong key type", pairValue->toStringWithType->EvString) } - }) + ) ->Js.Dict.fromArray ->EvRecord ->Ok diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index 951f444f..b18c927a 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -19,14 +19,10 @@ let dispatchMacroCall = ( environment, reduceExpression: ExpressionT.reducerFn, ): result => { - let doBindStatement = (bindingExpr: expression, statement: expression, environment) => + let doBindStatement = (bindingExpr: expression, statement: expression, environment) => switch statement { | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { - let rExternalBindingsValue = reduceExpression( - bindingExpr, - Bindings.defaultBindings, - environment, - ) + let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) rExternalBindingsValue->Result.flatMap(externalBindingsValue => { let newBindings = Bindings.fromValue(externalBindingsValue) @@ -41,13 +37,15 @@ let dispatchMacroCall = ( } | _ => REAssignmentExpected->Error } + - let doBindExpression = (bindingExpr: expression, statement: expression, environment) => + let doBindExpression = (bindingExpr: expression, statement: expression, environment) => switch statement { | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { let rExternalBindingsValue = reduceExpression( bindingExpr, - Bindings.defaultBindings, + Belt.Map.String.fromArray([("x", ExpressionValue.EvNumber(666.))]), + // bindingsToHandDown, environment, ) @@ -68,11 +66,7 @@ let dispatchMacroCall = ( }) } | _ => { - let rExternalBindingsValue = reduceExpression( - bindingExpr, - Bindings.defaultBindings, - environment, - ) + let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) rExternalBindingsValue->Result.flatMap(externalBindingsValue => { let newBindings = Bindings.fromValue(externalBindingsValue) let rNewStatement = Bindings.replaceSymbols(newBindings, statement) @@ -80,7 +74,7 @@ let dispatchMacroCall = ( }) } } - + let doBlock = (exprs: list, _bindings: ExpressionT.bindings, _environment): result< expression, errorValue, 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 e69c27d8..bbd7cc3b 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 @@ -32,7 +32,7 @@ let parse = (mathJsCode: string): result => let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result< expressionValue, 'e, -> => { +> => switch expression { | T.EValue(value) => value->Ok | T.EList(list) => @@ -46,7 +46,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en | _ => reduceExpressionList(list, bindings, environment) } } -} + and reduceExpressionList = ( expressions: list, bindings: T.bindings, diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res index ad83edb1..691a571c 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res @@ -8,11 +8,11 @@ external castString: unit => string = "%identity" /* As JavaScript returns us any type, we need to type check and cast type propertype before using it */ -let jsToEv = (jsValue): result => { +let jsToEv = (jsValue): result => switch Js.typeof(jsValue) { | "boolean" => jsValue->castBool->EvBool->Ok | "number" => jsValue->castNumber->EvNumber->Ok | "string" => jsValue->castString->EvString->Ok | other => RETodo(`Unhandled MathJs literal type: ${Js.String.make(other)}`)->Error } -} + diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index c782e6af..a5c5b22e 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -28,14 +28,14 @@ module Helpers = { let catchAndConvertTwoArgsToDists = (args: array): option<( DistributionTypes.genericDist, DistributionTypes.genericDist, - )> => { + )> => switch args { | [EvDistribution(a), EvDistribution(b)] => Some((a, b)) | [EvNumber(a), EvDistribution(b)] => Some((GenericDist.fromFloat(a), b)) | [EvDistribution(a), EvNumber(b)] => Some((a, GenericDist.fromFloat(b))) | _ => None } - } + let toFloatFn = ( fnCall: DistributionTypes.DistributionOperation.toFloat, @@ -119,7 +119,7 @@ module Helpers = { mixtureWithGivenWeights(distributions, weights) } - let mixture = (args: array): DistributionOperation.outputType => { + let mixture = (args: array): DistributionOperation.outputType => switch E.A.last(args) { | Some(EvArray(b)) => { let weights = parseNumberArray(b) @@ -138,7 +138,7 @@ module Helpers = { } | _ => GenDistError(ArgumentError("Last argument of mx must be array or distribution")) } - } + } module SymbolicConstructors = { From 3bbc5e7149d0a71a0f4274d9eaa845aef93b7277 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Fri, 29 Apr 2022 19:03:58 +0200 Subject: [PATCH 28/53] Add evaluate partial for back compatibility --- .../squiggle-lang/src/rescript/Reducer/Reducer.res | 1 + .../squiggle-lang/src/rescript/Reducer/Reducer.resi | 6 ++++++ .../Reducer_Expression/Reducer_Expression.res | 12 ++++++++++++ 3 files changed, 19 insertions(+) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res index c9c9f41e..24c985d8 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res @@ -11,4 +11,5 @@ type expressionValue = ReducerInterface_ExpressionValue.expressionValue type externalBindings = ReducerInterface_ExpressionValue.externalBindings let evaluate = Expression.evaluate let evaluateUsingOptions = Expression.evaluateUsingOptions +let evaluatePartialUsingExternalBindings = Expression.evaluatePartialUsingExternalBindings let parse = Expression.parse diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi index 880dd1e7..4e86361a 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi @@ -21,6 +21,12 @@ let evaluateUsingOptions: ( string, ) => result @genType +let evaluatePartialUsingExternalBindings: ( + string, + QuriSquiggleLang.ReducerInterface_ExpressionValue.externalBindings, + QuriSquiggleLang.ReducerInterface_ExpressionValue.environment, +) => result +@genType let evaluate: string => result let parse: string => result 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 bbd7cc3b..02043320 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 @@ -114,3 +114,15 @@ let evaluate = (code: string): result => { evaluateUsingOptions(~environment=None, ~externalBindings=None, code) } let eval = evaluate +let evaluatePartialUsingExternalBindings = ( + code: string, + externalBindings: ReducerInterface_ExpressionValue.externalBindings, + environment: ReducerInterface_ExpressionValue.environment, +): result => { + let rAnswer = evaluateUsingOptions(~environment=Some(environment), ~externalBindings=Some(externalBindings), code) + switch rAnswer { + | Ok(EvRecord(externalBindings)) => Ok(externalBindings) + | Ok(_) => Error(Reducer_ErrorValue.RESyntaxError(`Partials must end with an assignment or record`)) + | Error(err) => err->Error + } +} From bbe8eced29d5cb2adfc31072c20bce5032a9a276 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Fri, 29 Apr 2022 19:31:34 +0200 Subject: [PATCH 29/53] format --- .../Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res | 2 +- .../Reducer_Dispatch_BuiltInMacros.res | 7 +++---- .../Reducer_Expression/Reducer_Expression.res | 15 ++++++++++----- .../Reducer/Reducer_Js/Reducer_Js_Gate.res | 3 +-- .../ReducerInterface_GenericDistribution.res | 6 ++---- 5 files changed, 17 insertions(+), 16 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 0067441c..25fc05a7 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 @@ -21,7 +21,7 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> => } let constructRecord = arrayOfPairs => { - Belt.Array.map(arrayOfPairs, pairValue => + Belt.Array.map(arrayOfPairs, pairValue => switch pairValue { | EvArray([EvString(key), valueValue]) => (key, valueValue) | _ => ("wrong key type", pairValue->toStringWithType->EvString) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index b18c927a..f3f6d8c3 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -19,7 +19,7 @@ let dispatchMacroCall = ( environment, reduceExpression: ExpressionT.reducerFn, ): result => { - let doBindStatement = (bindingExpr: expression, statement: expression, environment) => + let doBindStatement = (bindingExpr: expression, statement: expression, environment) => switch statement { | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) @@ -37,9 +37,8 @@ let dispatchMacroCall = ( } | _ => REAssignmentExpected->Error } - - let doBindExpression = (bindingExpr: expression, statement: expression, environment) => + let doBindExpression = (bindingExpr: expression, statement: expression, environment) => switch statement { | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { let rExternalBindingsValue = reduceExpression( @@ -74,7 +73,7 @@ let dispatchMacroCall = ( }) } } - + let doBlock = (exprs: list, _bindings: ExpressionT.bindings, _environment): result< expression, errorValue, 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 02043320..5eeb51c7 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 @@ -32,7 +32,7 @@ let parse = (mathJsCode: string): result => let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result< expressionValue, 'e, -> => +> => switch expression { | T.EValue(value) => value->Ok | T.EList(list) => @@ -119,10 +119,15 @@ let evaluatePartialUsingExternalBindings = ( externalBindings: ReducerInterface_ExpressionValue.externalBindings, environment: ReducerInterface_ExpressionValue.environment, ): result => { - let rAnswer = evaluateUsingOptions(~environment=Some(environment), ~externalBindings=Some(externalBindings), code) + let rAnswer = evaluateUsingOptions( + ~environment=Some(environment), + ~externalBindings=Some(externalBindings), + code, + ) switch rAnswer { - | Ok(EvRecord(externalBindings)) => Ok(externalBindings) - | Ok(_) => Error(Reducer_ErrorValue.RESyntaxError(`Partials must end with an assignment or record`)) - | Error(err) => err->Error + | Ok(EvRecord(externalBindings)) => Ok(externalBindings) + | Ok(_) => + Error(Reducer_ErrorValue.RESyntaxError(`Partials must end with an assignment or record`)) + | Error(err) => err->Error } } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res index 691a571c..7cd220bc 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res @@ -8,11 +8,10 @@ external castString: unit => string = "%identity" /* As JavaScript returns us any type, we need to type check and cast type propertype before using it */ -let jsToEv = (jsValue): result => +let jsToEv = (jsValue): result => switch Js.typeof(jsValue) { | "boolean" => jsValue->castBool->EvBool->Ok | "number" => jsValue->castNumber->EvNumber->Ok | "string" => jsValue->castString->EvString->Ok | other => RETodo(`Unhandled MathJs literal type: ${Js.String.make(other)}`)->Error } - diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index a5c5b22e..0bfd3cba 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -28,14 +28,13 @@ module Helpers = { let catchAndConvertTwoArgsToDists = (args: array): option<( DistributionTypes.genericDist, DistributionTypes.genericDist, - )> => + )> => switch args { | [EvDistribution(a), EvDistribution(b)] => Some((a, b)) | [EvNumber(a), EvDistribution(b)] => Some((GenericDist.fromFloat(a), b)) | [EvDistribution(a), EvNumber(b)] => Some((a, GenericDist.fromFloat(b))) | _ => None } - let toFloatFn = ( fnCall: DistributionTypes.DistributionOperation.toFloat, @@ -119,7 +118,7 @@ module Helpers = { mixtureWithGivenWeights(distributions, weights) } - let mixture = (args: array): DistributionOperation.outputType => + let mixture = (args: array): DistributionOperation.outputType => switch E.A.last(args) { | Some(EvArray(b)) => { let weights = parseNumberArray(b) @@ -138,7 +137,6 @@ module Helpers = { } | _ => GenDistError(ArgumentError("Last argument of mx must be array or distribution")) } - } module SymbolicConstructors = { From 2c452163b6593d90b8364e9134e5f7090744521f Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Fri, 29 Apr 2022 14:41:30 -0400 Subject: [PATCH 30/53] I believe I have functionality in place for new `run` command, but I could be wrong. Pushing so Sam can review Value: [1e-5 to 9e-3] --- packages/squiggle-lang/src/js/index.ts | 30 ++++++++++++------- .../ReducerInterface_GenericDistribution.res | 8 +++-- .../ReducerInterface_GenericDistribution.resi | 1 + .../src/rescript/TypescriptInterface.res | 12 ++++++++ 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 34318424..98a79b84 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -2,9 +2,11 @@ import * as _ from "lodash"; import { genericDist, samplingParams, + environment, evaluatePartialUsingExternalBindings, externalBindings, expressionValue, + recordEV, errorValue, distributionError, toPointSet, @@ -15,6 +17,8 @@ import { mixedShape, sampleSetDist, symbolicDist, + defaultEnvironment, + defaultSamplingEnv, } from "../rescript/TypescriptInterface.gen"; export { makeSampleSetDist, @@ -50,10 +54,7 @@ import { } from "../rescript/Distributions/DistributionOperation/DistributionOperation.gen"; export type { samplingParams, errorValue, externalBindings as bindings }; -export let defaultSamplingInputs: samplingParams = { - sampleCount: 10000, - xyPointLength: 10000, -}; +export let defaultSamplingInputs: samplingParams = defaultSamplingEnv; export type result = | { @@ -90,8 +91,9 @@ export type squiggleExpression = | tagged<"symbol", string> | tagged<"string", string> | tagged<"call", string> - | tagged<"lambda", [string[], internalCode]> + | tagged<"lambda", [string[], recordEV, internalCode]> | tagged<"array", squiggleExpression[]> + | tagged<"arrayString", string[]> | tagged<"boolean", boolean> | tagged<"distribution", Distribution> | tagged<"number", number> @@ -100,16 +102,16 @@ export type squiggleExpression = export function run( squiggleString: string, bindings?: externalBindings, - samplingInputs?: samplingParams + samplingInputs?: samplingParams, + environ?: environment ): result { let b = bindings ? bindings : {}; let si: samplingParams = samplingInputs ? samplingInputs : defaultSamplingInputs; - - let result: result = - evaluateUsingExternalBindings(squiggleString, b); - return resultMap(result, (x) => createTsExport(x, si)); + let e = environ ? environ : defaultEnvironment; + let res: result = eval(squiggleString); // , b, e); + return resultMap(res, (x) => createTsExport(x, si)); } // Run Partial. A partial is a block of code that doesn't return a value @@ -118,7 +120,11 @@ export function runPartial( bindings: externalBindings, _samplingInputs?: samplingParams ): result { - return evaluatePartialUsingExternalBindings(squiggleString, bindings); + return evaluatePartialUsingExternalBindings( + squiggleString, + bindings, + defaultEnvironment + ); } function createTsExport( @@ -158,6 +164,8 @@ function createTsExport( } }) ); + case "EvArrayString": + return tag("arrayString", x.value); case "EvBool": return tag("boolean", x.value); case "EvCall": diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index a5c5b22e..ceac0800 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -1,11 +1,13 @@ module ExpressionValue = ReducerInterface_ExpressionValue type expressionValue = ReducerInterface_ExpressionValue.expressionValue -let runGenericOperation = DistributionOperation.run( - ~env={ +let defaultEnv: DistributionOperation.env = { sampleCount: MagicNumbers.Environment.defaultSampleCount, xyPointLength: MagicNumbers.Environment.defaultXYPointLength, - }, + } + +let runGenericOperation = DistributionOperation.run( + ~env=defaultEnv, ) module Helpers = { diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi index 7f26a610..038f4479 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.resi @@ -1,3 +1,4 @@ +let defaultEnv: DistributionOperation.env let dispatch: ( ReducerInterface_ExpressionValue.functionCall, ReducerInterface_ExpressionValue.environment, diff --git a/packages/squiggle-lang/src/rescript/TypescriptInterface.res b/packages/squiggle-lang/src/rescript/TypescriptInterface.res index 70f3a3d1..114dc4e6 100644 --- a/packages/squiggle-lang/src/rescript/TypescriptInterface.res +++ b/packages/squiggle-lang/src/rescript/TypescriptInterface.res @@ -49,6 +49,9 @@ type externalBindings = Reducer.externalBindings @genType type expressionValue = ReducerInterface_ExpressionValue.expressionValue +@genType +type recordEV = ReducerInterface_ExpressionValue.record + @genType type errorValue = Reducer_ErrorValue.errorValue @@ -72,3 +75,12 @@ let distributionErrorToString = DistributionTypes.Error.toString @genType type internalCode = ReducerInterface_ExpressionValue.internalCode + +@genType +let defaultSamplingEnv = ReducerInterface_GenericDistribution.defaultEnv + +@genType +type environment = ReducerInterface_ExpressionValue.environment + +@genType +let defaultEnvironment = ReducerInterface_ExpressionValue.defaultEnvironment From 0e9996256e02350383ab3e31a41ad8444b567f59 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Fri, 29 Apr 2022 14:42:34 -0400 Subject: [PATCH 31/53] Lint for Umur Value: [1e-8 to 1e-6] --- .../Reducer_Dispatch_BuiltIn.res | 2 +- .../Reducer_Dispatch_BuiltInMacros.res | 7 +++---- .../Reducer_Expression/Reducer_Expression.res | 15 ++++++++++----- .../Reducer/Reducer_Js/Reducer_Js_Gate.res | 3 +-- .../ReducerInterface_GenericDistribution.res | 16 ++++++---------- 5 files changed, 21 insertions(+), 22 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 0067441c..25fc05a7 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 @@ -21,7 +21,7 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> => } let constructRecord = arrayOfPairs => { - Belt.Array.map(arrayOfPairs, pairValue => + Belt.Array.map(arrayOfPairs, pairValue => switch pairValue { | EvArray([EvString(key), valueValue]) => (key, valueValue) | _ => ("wrong key type", pairValue->toStringWithType->EvString) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index b18c927a..f3f6d8c3 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -19,7 +19,7 @@ let dispatchMacroCall = ( environment, reduceExpression: ExpressionT.reducerFn, ): result => { - let doBindStatement = (bindingExpr: expression, statement: expression, environment) => + let doBindStatement = (bindingExpr: expression, statement: expression, environment) => switch statement { | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) @@ -37,9 +37,8 @@ let dispatchMacroCall = ( } | _ => REAssignmentExpected->Error } - - let doBindExpression = (bindingExpr: expression, statement: expression, environment) => + let doBindExpression = (bindingExpr: expression, statement: expression, environment) => switch statement { | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { let rExternalBindingsValue = reduceExpression( @@ -74,7 +73,7 @@ let dispatchMacroCall = ( }) } } - + let doBlock = (exprs: list, _bindings: ExpressionT.bindings, _environment): result< expression, errorValue, 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 02043320..5eeb51c7 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 @@ -32,7 +32,7 @@ let parse = (mathJsCode: string): result => let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result< expressionValue, 'e, -> => +> => switch expression { | T.EValue(value) => value->Ok | T.EList(list) => @@ -119,10 +119,15 @@ let evaluatePartialUsingExternalBindings = ( externalBindings: ReducerInterface_ExpressionValue.externalBindings, environment: ReducerInterface_ExpressionValue.environment, ): result => { - let rAnswer = evaluateUsingOptions(~environment=Some(environment), ~externalBindings=Some(externalBindings), code) + let rAnswer = evaluateUsingOptions( + ~environment=Some(environment), + ~externalBindings=Some(externalBindings), + code, + ) switch rAnswer { - | Ok(EvRecord(externalBindings)) => Ok(externalBindings) - | Ok(_) => Error(Reducer_ErrorValue.RESyntaxError(`Partials must end with an assignment or record`)) - | Error(err) => err->Error + | Ok(EvRecord(externalBindings)) => Ok(externalBindings) + | Ok(_) => + Error(Reducer_ErrorValue.RESyntaxError(`Partials must end with an assignment or record`)) + | Error(err) => err->Error } } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res index 691a571c..7cd220bc 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Js/Reducer_Js_Gate.res @@ -8,11 +8,10 @@ external castString: unit => string = "%identity" /* As JavaScript returns us any type, we need to type check and cast type propertype before using it */ -let jsToEv = (jsValue): result => +let jsToEv = (jsValue): result => switch Js.typeof(jsValue) { | "boolean" => jsValue->castBool->EvBool->Ok | "number" => jsValue->castNumber->EvNumber->Ok | "string" => jsValue->castString->EvString->Ok | other => RETodo(`Unhandled MathJs literal type: ${Js.String.make(other)}`)->Error } - diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index ceac0800..d5926d0f 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -2,13 +2,11 @@ module ExpressionValue = ReducerInterface_ExpressionValue type expressionValue = ReducerInterface_ExpressionValue.expressionValue let defaultEnv: DistributionOperation.env = { - sampleCount: MagicNumbers.Environment.defaultSampleCount, - xyPointLength: MagicNumbers.Environment.defaultXYPointLength, - } + sampleCount: MagicNumbers.Environment.defaultSampleCount, + xyPointLength: MagicNumbers.Environment.defaultXYPointLength, +} -let runGenericOperation = DistributionOperation.run( - ~env=defaultEnv, -) +let runGenericOperation = DistributionOperation.run(~env=defaultEnv) module Helpers = { let arithmeticMap = r => @@ -30,14 +28,13 @@ module Helpers = { let catchAndConvertTwoArgsToDists = (args: array): option<( DistributionTypes.genericDist, DistributionTypes.genericDist, - )> => + )> => switch args { | [EvDistribution(a), EvDistribution(b)] => Some((a, b)) | [EvNumber(a), EvDistribution(b)] => Some((GenericDist.fromFloat(a), b)) | [EvDistribution(a), EvNumber(b)] => Some((a, GenericDist.fromFloat(b))) | _ => None } - let toFloatFn = ( fnCall: DistributionTypes.DistributionOperation.toFloat, @@ -121,7 +118,7 @@ module Helpers = { mixtureWithGivenWeights(distributions, weights) } - let mixture = (args: array): DistributionOperation.outputType => + let mixture = (args: array): DistributionOperation.outputType => switch E.A.last(args) { | Some(EvArray(b)) => { let weights = parseNumberArray(b) @@ -140,7 +137,6 @@ module Helpers = { } | _ => GenDistError(ArgumentError("Last argument of mx must be array or distribution")) } - } module SymbolicConstructors = { From f05d08952439d0d98da99d7d02f24152b78fadb0 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Fri, 29 Apr 2022 15:02:24 -0400 Subject: [PATCH 32/53] Fixed most tests Value: [1e-5 to 1e-3] --- packages/squiggle-lang/src/js/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 98a79b84..5bd02f67 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -4,6 +4,7 @@ import { samplingParams, environment, evaluatePartialUsingExternalBindings, + evaluateUsingOptions, externalBindings, expressionValue, recordEV, @@ -110,7 +111,10 @@ export function run( ? samplingInputs : defaultSamplingInputs; let e = environ ? environ : defaultEnvironment; - let res: result = eval(squiggleString); // , b, e); + let res: result = evaluateUsingOptions( + { externalBindings: b, environment: e }, + squiggleString + ); // , b, e); return resultMap(res, (x) => createTsExport(x, si)); } From 8b30eb9f054f1ab01945c74fd1a592837cf26d16 Mon Sep 17 00:00:00 2001 From: Quinn Dougherty Date: Fri, 29 Apr 2022 15:25:29 -0400 Subject: [PATCH 33/53] Added to convertRaw* stuff Value: [1e-4 to 1e-3] --- packages/squiggle-lang/src/js/index.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 5bd02f67..b944bc80 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -231,6 +231,8 @@ function convertRawToTypescript( return tag("string", result._0); case 7: // EvSymbol return tag("symbol", result._0); + case 8: // EvArrayString + return tag("arrayString", result._0); } } @@ -287,6 +289,10 @@ type rescriptExport = | { TAG: 7; // EvSymbol _0: string; + } + | { + TAG: 8; // EvArrayString + _0: string[]; }; type rescriptDist = From 76b3adddc4a511a00982b467c1cc7a9e586814de Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 11:12:12 +0200 Subject: [PATCH 34/53] rename to exampleStatementY --- .../Reducer_Dispatch_BuiltInMacros_test.res | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res index eb6e6c0d..f0393103 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res @@ -7,7 +7,7 @@ module ExpressionT = Reducer_Expression_T let exampleExpression = eNumber(1.) let exampleExpressionY = eSymbol("y") -let exampleStatement = eLetStatement("y", eNumber(1.)) +let exampleStatementY = eLetStatement("y", eNumber(1.)) let exampleStatementX = eLetStatement("y", eSymbol("x")) let exampleStatementZ = eLetStatement("z", eSymbol("y")) @@ -16,9 +16,9 @@ testMacro([], exampleExpression, "Ok(1)") describe("bindStatement", () => { // A statement is bound by the bindings created by the previous statement - testMacro([], eBindStatement(eBindings([]), exampleStatement), "Ok((:$setBindings {} :y 1))") + testMacro([], eBindStatement(eBindings([]), exampleStatementY), "Ok((:$setBindings {} :y 1))") // Then it answers the bindings for the next statement when reduced - testMacroEval([], eBindStatement(eBindings([]), exampleStatement), "Ok({y: 1})") + testMacroEval([], eBindStatement(eBindings([]), exampleStatementY), "Ok({y: 1})") // Now let's feed a binding to see what happens testMacro( [], @@ -30,7 +30,7 @@ describe("bindStatement", () => { // When bindings from previous statement are missing the context is injected. This must be the first statement of a block testMacro( [("z", EvNumber(99.))], - eBindStatementDefault(exampleStatement), + eBindStatementDefault(exampleStatementY), "Ok((:$setBindings {z: 99} :y 1))", ) }) @@ -41,19 +41,19 @@ describe("bindExpression", () => { // When an let statement is the end expression then bindings are returned testMacro( [], - eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatement), + eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatementY), "Ok((:$exportBindings (:$setBindings {x: 2} :y 1)))", ) // Now let's reduce that expression testMacroEval( [], - eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatement), + eBindExpression(eBindings([("x", EvNumber(2.))]), exampleStatementY), "Ok({x: 2,y: 1})", ) // When bindings are missing the context is injected. This must be the first and last statement of a block testMacroEval( [("z", EvNumber(99.))], - eBindExpressionDefault(exampleStatement), + eBindExpressionDefault(exampleStatementY), "Ok({y: 1,z: 99})", ) }) @@ -63,22 +63,22 @@ describe("block", () => { testMacro([], eBlock(list{exampleExpression}), "Ok((:$$bindExpression 1))") testMacroEval([], eBlock(list{exampleExpression}), "Ok(1)") // Block with a single statement - testMacro([], eBlock(list{exampleStatement}), "Ok((:$$bindExpression (:$let :y 1)))") - testMacroEval([], eBlock(list{exampleStatement}), "Ok({y: 1})") + testMacro([], eBlock(list{exampleStatementY}), "Ok((:$$bindExpression (:$let :y 1)))") + testMacroEval([], eBlock(list{exampleStatementY}), "Ok({y: 1})") // Block with a statement and an expression testMacro( [], - eBlock(list{exampleStatement, exampleExpressionY}), + eBlock(list{exampleStatementY, exampleExpressionY}), "Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) :y))", ) - testMacroEval([], eBlock(list{exampleStatement, exampleExpressionY}), "Ok(1)") + testMacroEval([], eBlock(list{exampleStatementY, exampleExpressionY}), "Ok(1)") // Block with a statement and another statement testMacro( [], - eBlock(list{exampleStatement, exampleStatementZ}), + eBlock(list{exampleStatementY, exampleStatementZ}), "Ok((:$$bindExpression (:$$bindStatement (:$let :y 1)) (:$let :z :y)))", ) - testMacroEval([], eBlock(list{exampleStatement, exampleStatementZ}), "Ok({y: 1,z: 1})") + testMacroEval([], eBlock(list{exampleStatementY, exampleStatementZ}), "Ok({y: 1,z: 1})") // Block inside a block testMacro( [], From e262f76d9852715290284cc611b37c3fdf4c4a60 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 11:20:08 +0200 Subject: [PATCH 35/53] spelling --- .../Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res index f0393103..7bbc43dd 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros_test.res @@ -11,7 +11,7 @@ let exampleStatementY = eLetStatement("y", eNumber(1.)) let exampleStatementX = eLetStatement("y", eSymbol("x")) let exampleStatementZ = eLetStatement("z", eSymbol("y")) -// If it is not a mactro then it is not expanded +// If it is not a macro then it is not expanded testMacro([], exampleExpression, "Ok(1)") describe("bindStatement", () => { From 6796db82b4d7e7507e228bf2bd416176e1ad6380 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 11:38:32 +0200 Subject: [PATCH 36/53] note weird distribution test --- .../ReducerInterface/ReducerInterface_Distribution_test.res | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res index 2c0cc3e6..bb330479 100644 --- a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res +++ b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res @@ -132,7 +132,8 @@ describe("parse on distribution functions", () => { testParse( ~skip=true, "normal(5,2) .- normal(5,1)", - "Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))", + "Ok((:$$block (:dotSubtract (:normal 5 2) (:normal 5 1))))", + // TODO: !!! returns "Ok((:$$block (:dotPow (:normal 5 2) (:normal 5 1))))" ) testParse( "normal(5,2) .* normal(5,1)", From 087596ec432570bf446117552b000de7ea9d1701 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 11:43:09 +0200 Subject: [PATCH 37/53] function trics --- .../__tests__/Reducer/Reducer_functionTricks_test.res | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res new file mode 100644 index 00000000..7b6b7097 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -0,0 +1,6 @@ +open Jest +open Reducer_TestHelpers + +describe("function trics", () => { + testEvalToBe("1", "Ok(1)") +}) \ No newline at end of file From c0fad8c668705ab112b07dc9dd622ef8a366f3d5 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 12:10:31 +0200 Subject: [PATCH 38/53] define lambdaValue record as payload --- .../Reducer_Expression_ExpressionBuilder.res | 8 ++++---- .../Reducer_Expression_Lambda.res | 4 ++-- .../ReducerInterface_ExpressionValue.res | 16 ++++++++++------ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res index ec3a0214..989d2810 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res @@ -26,10 +26,10 @@ let eFunction = (fName: string, lispArgs: list): expression => { } let eLambda = (parameters: array, context, expr) => - BExpressionValue.EvLambda( - parameters, - context, - expr->castExpressionToInternalCode, + BExpressionValue.EvLambda({ + parameters: parameters, + context: context, + body: expr->castExpressionToInternalCode} )->BExpressionT.EValue let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res index a2d795c0..675e3bc3 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res @@ -30,6 +30,6 @@ let applyParametersToLambda = ( reducer(newExpression, bindings, environment) } -let doLambdaCall = ((parameters, context, internal), args, environment, reducer) => { - applyParametersToLambda(internal, parameters, args, context, environment, reducer) +let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) => { + applyParametersToLambda(lambdaValue.body, lambdaValue.parameters, args, lambdaValue.context, environment, reducer) } diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 31168425..ddf2cd48 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -15,15 +15,19 @@ type rec expressionValue = | EvBool(bool) | EvCall(string) // External function call | EvDistribution(DistributionTypes.genericDist) - | EvLambda((array, record, internalCode)) + | EvLambda(lambdaValue) | EvNumber(float) | EvRecord(record) | EvString(string) | EvSymbol(string) and record = Js.Dict.t +and externalBindings = record +and lambdaValue = { + parameters: array, + context: externalBindings, + body: internalCode, +} -@genType -type externalBindings = record @genType let defaultExternalBindings: externalBindings = Js.Dict.empty() @@ -41,8 +45,8 @@ let rec toString = aValue => } | EvBool(aBool) => Js.String.make(aBool) | EvCall(fName) => `:${fName}` - | EvLambda((parameters, _context, _internalCode)) => - `lambda(${Js.Array2.toString(parameters)}=>internal)` + | EvLambda(lambdaValue) => + `lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)` | EvNumber(aNumber) => Js.String.make(aNumber) | EvString(aString) => `'${aString}'` | EvSymbol(aString) => `:${aString}` @@ -65,7 +69,7 @@ let toStringWithType = aValue => | EvBool(_) => `Bool::${toString(aValue)}` | EvCall(_) => `Call::${toString(aValue)}` | EvDistribution(_) => `Distribution::${toString(aValue)}` - | EvLambda((_parameters, _context, _internalCode)) => `Lambda::${toString(aValue)}` + | EvLambda(_) => `Lambda::${toString(aValue)}` | EvNumber(_) => `Number::${toString(aValue)}` | EvRecord(_) => `Record::${toString(aValue)}` | EvString(_) => `String::${toString(aValue)}` From 1e673e54c33d078beb695de40a4e45dfcffec180 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 12:23:37 +0200 Subject: [PATCH 39/53] function tricks test defined (Sam's trials) --- .../Reducer/Reducer_functionTricks_test.res | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index 7b6b7097..69e20067 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -1,6 +1,17 @@ open Jest open Reducer_TestHelpers -describe("function trics", () => { - testEvalToBe("1", "Ok(1)") +Skip.describe("function trics", () => { + testEvalToBe("f(x,y)=x(y); f(f)", "????") + testEvalToBe("f(x)=x(y); f(f)", "????") + testEvalToBe("f(x)=x; f(f)", "????") + + testEvalToBe("f(x,y)=x(y); f(z)", "????") + testEvalToBe("f(x,y)=x(y); f(2)", "????") //prevent js error + testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment + testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found + testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found + testEvalToBe("y=2;g(x)=inspect(y)+1", "????") //TODO : 666 + testEvalToBe("f(x,y)=x+y; f(1,2,3,4)", "????") //TODO : arity)) + testEvalToBe("f(x,y)=x+y; f(1)", "????") //TODO : arity)) }) \ No newline at end of file From c68138e5f6f8d8c8f061d6b467bf23a44a568a45 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 12:55:28 +0200 Subject: [PATCH 40/53] arity error --- .../Reducer/Reducer_functionTricks_test.res | 51 +++++++++++++----- .../rescript/Reducer/Reducer_ErrorValue.res | 7 ++- .../Reducer_Expression_ExpressionBuilder.res | 4 +- .../Reducer_Expression_Lambda.res | 53 ++++++++++++++----- .../ReducerInterface_ExpressionValue.res | 3 +- 5 files changed, 86 insertions(+), 32 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index 69e20067..23b4eaba 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -1,17 +1,42 @@ open Jest open Reducer_TestHelpers -Skip.describe("function trics", () => { - testEvalToBe("f(x,y)=x(y); f(f)", "????") - testEvalToBe("f(x)=x(y); f(f)", "????") - testEvalToBe("f(x)=x; f(f)", "????") +describe("Arity check", () => { + testEvalToBe("f(x,y) = x + y; f(1,2)", "Ok(3)") + testEvalToBe( + "f(x,y) = x + y; f(1)", + "Error(2 arguments expected. Instead 1 argument(s) were passed.)", + ) + testEvalToBe( + "f(x,y) = x + y; f(1,2,3)", + "Error(2 arguments expected. Instead 3 argument(s) were passed.)", + ) + testEvalToBe( + "f(x,y)=x+y; f(1,2,3,4)", + "Error(2 arguments expected. Instead 4 argument(s) were passed.)", + ) + testEvalToBe( + "f(x,y)=x+y; f(1)", + "Error(2 arguments expected. Instead 1 argument(s) were passed.)", + ) + testEvalToBe( + "f(x,y)=x(y); f(f)", + "Error(2 arguments expected. Instead 1 argument(s) were passed.)", + ) + testEvalToBe("f(x)=x; f(f)", "Ok(lambda(x=>internal code))") + testEvalToBe( + "f(x,y)=x(y); f(z)", + "Error(2 arguments expected. Instead 1 argument(s) were passed.)", + ) +}) - testEvalToBe("f(x,y)=x(y); f(z)", "????") - testEvalToBe("f(x,y)=x(y); f(2)", "????") //prevent js error - testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment - testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found - testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found - testEvalToBe("y=2;g(x)=inspect(y)+1", "????") //TODO : 666 - testEvalToBe("f(x,y)=x+y; f(1,2,3,4)", "????") //TODO : arity)) - testEvalToBe("f(x,y)=x+y; f(1)", "????") //TODO : arity)) -}) \ No newline at end of file +describe("function trics", () => { + testEvalToBe("f(x)=x(y); f(f)", "Error(y is not defined)") + testEvalToBe("f(x)=x; f(f)", "Ok(lambda(x=>internal code))") + testEvalToBe("f(x)=x(y); f(z)", "Error(y is not defined)") + MySkip.testEvalToBe("f(x)=x(y); f(2)", "????") //prevent js error + MySkip.testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment + MySkip.testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found + MySkip.testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found + MySkip.testEvalToBe("y=2;g(x)=inspect(y)+1", "????") //TODO : 666 +}) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index 96b73fd2..b9eabe28 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -1,7 +1,9 @@ @genType type errorValue = + | REArityError(option, int, int) //TODO: Binding a lambda to a variable should record the variable name in lambda for error reporting | REArrayIndexNotFound(string, int) | REAssignmentExpected + | REDistributionError(DistributionTypes.error) | REExpressionExpected | REFunctionExpected(string) | REJavaScriptExn(option, option) // Javascript Exception @@ -9,7 +11,6 @@ type errorValue = | RERecordPropertyNotFound(string, string) | RESymbolNotFound(string) | RESyntaxError(string) - | REDistributionError(DistributionTypes.error) | RETodo(string) // To do type t = errorValue @@ -17,6 +18,10 @@ type t = errorValue @genType let errorToString = err => switch err { + | REArityError(_oFnName, arity, usedArity) => + `${Js.String.make(arity)} arguments expected. Instead ${Js.String.make( + usedArity, + )} argument(s) were passed.` | REArrayIndexNotFound(msg, index) => `${msg}: ${Js.String.make(index)}` | REAssignmentExpected => "Assignment expected" | REExpressionExpected => "Expression expected" diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res index 989d2810..3aa0fcba 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res @@ -29,8 +29,8 @@ let eLambda = (parameters: array, context, expr) => BExpressionValue.EvLambda({ parameters: parameters, context: context, - body: expr->castExpressionToInternalCode} - )->BExpressionT.EValue + body: expr->castExpressionToInternalCode, + })->BExpressionT.EValue let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res index 675e3bc3..55931cc7 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Lambda.res @@ -1,7 +1,9 @@ module Bindings = Reducer_Expression_Bindings +module ErrorValue = Reducer_ErrorValue module ExpressionBuilder = Reducer_Expression_ExpressionBuilder module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface.ExpressionValue +module Result = Belt.Result type environment = ReducerInterface_ExpressionValue.environment type expression = ExpressionT.expression @@ -11,25 +13,48 @@ type internalCode = ReducerInterface_ExpressionValue.internalCode external castInternalCodeToExpression: internalCode => expression = "%identity" +let checkArity = (lambdaValue: ExpressionValue.lambdaValue, args: list) => { + let argsLength = Belt.List.length(args) + let parametersLength = Js.Array2.length(lambdaValue.parameters) + if argsLength !== parametersLength { + ErrorValue.REArityError(None, parametersLength, argsLength)->Error + } else { + args->Ok + } +} + +let checkIfReduced = (args: list) => + args->Belt.List.reduceReverse(Ok(list{}), (rAcc, arg) => + rAcc->Result.flatMap(acc => + switch arg { + | EvSymbol(symbol) => ErrorValue.RESymbolNotFound(symbol)->Error + | _ => list{arg, ...acc}->Ok + } + ) + ) + let applyParametersToLambda = ( - internal: internalCode, - parameters: array, - args: list, - context: externalBindings, + lambdaValue: ExpressionValue.lambdaValue, + args, environment, reducer: ExpressionT.reducerFn, ): result => { - let expr = castInternalCodeToExpression(internal) - let parameterList = parameters->Belt.List.fromArray - let zippedParameterList = parameterList->Belt.List.zip(args) - let bindings = Belt.List.reduce(zippedParameterList, context->Bindings.fromExternalBindings, ( - acc, - (variable, variableValue), - ) => acc->Belt.Map.String.set(variable, variableValue)) - let newExpression = ExpressionBuilder.eBlock(list{expr}) - reducer(newExpression, bindings, environment) + checkArity(lambdaValue, args)->Result.flatMap(args => + checkIfReduced(args)->Result.flatMap(args => { + let expr = castInternalCodeToExpression(lambdaValue.body) + let parameterList = lambdaValue.parameters->Belt.List.fromArray + let zippedParameterList = parameterList->Belt.List.zip(args) + let bindings = Belt.List.reduce( + zippedParameterList, + lambdaValue.context->Bindings.fromExternalBindings, + (acc, (variable, variableValue)) => acc->Belt.Map.String.set(variable, variableValue), + ) + let newExpression = ExpressionBuilder.eBlock(list{expr}) + reducer(newExpression, bindings, environment) + }) + ) } let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) => { - applyParametersToLambda(lambdaValue.body, lambdaValue.parameters, args, lambdaValue.context, environment, reducer) + applyParametersToLambda(lambdaValue, args, environment, reducer) } diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index 4d6911af..5c9ee4b7 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -45,8 +45,7 @@ let rec toString = aValue => } | EvBool(aBool) => Js.String.make(aBool) | EvCall(fName) => `:${fName}` - | EvLambda(lambdaValue) => - `lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)` + | EvLambda(lambdaValue) => `lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)` | EvNumber(aNumber) => Js.String.make(aNumber) | EvString(aString) => `'${aString}'` | EvSymbol(aString) => `:${aString}` From ba104e4dfea682094ddfcfdd8e5cbb9587198d19 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 15:22:01 +0200 Subject: [PATCH 41/53] Catching unreduced values. This is not a lazy language --- .../__tests__/Reducer/Reducer_functionTricks_test.res | 5 +++-- .../Reducer/Reducer_Expression/Reducer_Expression.res | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index 23b4eaba..9e3e25c2 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -33,8 +33,9 @@ describe("Arity check", () => { describe("function trics", () => { testEvalToBe("f(x)=x(y); f(f)", "Error(y is not defined)") testEvalToBe("f(x)=x; f(f)", "Ok(lambda(x=>internal code))") - testEvalToBe("f(x)=x(y); f(z)", "Error(y is not defined)") - MySkip.testEvalToBe("f(x)=x(y); f(2)", "????") //prevent js error + testEvalToBe("f(x)=x(y); f(z)", "Error(z is not defined)") + testEvalToBe("f(x)=x(y); f(2)", "Error(y is not defined)") + MySkip.testEvalToBe("f(x)=x(1); f(2)", "????") MySkip.testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment MySkip.testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found MySkip.testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found 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 5eeb51c7..bb201985 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 @@ -79,7 +79,12 @@ and reduceValueList = (valueList: list, environment): result< | list{EvLambda(lamdaCall), ...args} => Lambda.doLambdaCall(lamdaCall, args, environment, reduceExpression) - | _ => valueList->Belt.List.toArray->ExpressionValue.EvArray->Ok + | _ => + valueList + ->Lambda.checkIfReduced + ->Result.flatMap(reducedValueList => + reducedValueList->Belt.List.toArray->ExpressionValue.EvArray->Ok + ) } let evalUsingBindingsExpression_ = (aExpression, bindings, environment): result< From 9e41f0399f32670de196468ec17659aa73cd47e7 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 15:47:35 +0200 Subject: [PATCH 42/53] RENotAFunction --- .../__tests__/Reducer/Reducer_functionTricks_test.res | 4 ++-- .../src/rescript/Reducer/Reducer_ErrorValue.res | 2 ++ .../Reducer_Expression/Reducer_Expression_Bindings.res | 10 +++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index 9e3e25c2..b21b14cd 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -34,8 +34,8 @@ describe("function trics", () => { testEvalToBe("f(x)=x(y); f(f)", "Error(y is not defined)") testEvalToBe("f(x)=x; f(f)", "Ok(lambda(x=>internal code))") testEvalToBe("f(x)=x(y); f(z)", "Error(z is not defined)") - testEvalToBe("f(x)=x(y); f(2)", "Error(y is not defined)") - MySkip.testEvalToBe("f(x)=x(1); f(2)", "????") + testEvalToBe("f(x)=x(y); f(2)", "Error(2 is not a function)") + testEvalToBe("f(x)=x(1); f(2)", "Error(2 is not a function)") MySkip.testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment MySkip.testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found MySkip.testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index b9eabe28..7964c3a4 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -8,6 +8,7 @@ type errorValue = | REFunctionExpected(string) | REJavaScriptExn(option, option) // Javascript Exception | REMacroNotFound(string) + | RENotAFunction(string) | RERecordPropertyNotFound(string, string) | RESymbolNotFound(string) | RESyntaxError(string) @@ -40,6 +41,7 @@ let errorToString = err => answer } | REMacroNotFound(macro) => `Macro not found: ${macro}` + | RENotAFunction(valueString) => `${valueString} is not a function` | RERecordPropertyNotFound(msg, index) => `${msg}: ${index}` | RESymbolNotFound(symbolName) => `${symbolName} is not defined` | RESyntaxError(desc) => `Syntax Error: ${desc}` diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res index add7f614..830e93ba 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res @@ -1,3 +1,4 @@ +module ErrorValue = Reducer_ErrorValue module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface.ExpressionValue module Result = Belt.Result @@ -67,7 +68,14 @@ and replaceSymbolsOnExpressionList = (bindings, list) => { } and replaceSymbolOnValue = (bindings, evValue: expressionValue) => switch evValue { - | EvSymbol(symbol) | EvCall(symbol) => + | EvSymbol(symbol) => Belt.Map.String.getWithDefault(bindings, symbol, evValue)->Ok + | EvCall(symbol) => + Belt.Map.String.getWithDefault(bindings, symbol, evValue)->checkIfCallable | _ => evValue->Ok } +and checkIfCallable = (evValue: expressionValue) => + switch evValue { + | EvCall(_) | EvLambda(_) => evValue->Ok + | _ => ErrorValue.RENotAFunction(ExpressionValue.toString(evValue))->Error + } From f5d3da4c735c63c6e761f4f2c528b1cab51afea8 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 15:54:16 +0200 Subject: [PATCH 43/53] tests --- .../__tests__/Reducer/Reducer_functionTricks_test.res | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index b21b14cd..1f5b6968 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -36,8 +36,9 @@ describe("function trics", () => { testEvalToBe("f(x)=x(y); f(z)", "Error(z is not defined)") testEvalToBe("f(x)=x(y); f(2)", "Error(2 is not a function)") testEvalToBe("f(x)=x(1); f(2)", "Error(2 is not a function)") + MySkip.testParseToBe("f(x)=f(y)=2; f(2)", "????") MySkip.testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment - MySkip.testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found + testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found MySkip.testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found MySkip.testEvalToBe("y=2;g(x)=inspect(y)+1", "????") //TODO : 666 }) From 946b38fa2731101585f77689f24070eaaf54a271 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Mon, 2 May 2022 14:53:16 +0000 Subject: [PATCH 44/53] Fix Typescript build errors --- packages/squiggle-lang/package.json | 4 +- packages/squiggle-lang/src/js/index.ts | 51 ------------------- .../squiggle-lang/src/js/rescript_interop.ts | 7 ++- .../Distributions/DistributionTypes.res | 1 + .../src/rescript/TypescriptInterface.res | 2 +- 5 files changed, 8 insertions(+), 57 deletions(-) diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index 40f7e7c7..67dfed03 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -4,7 +4,9 @@ "homepage": "https://squiggle-language.com", "license": "MIT", "scripts": { - "build": "rescript build -with-deps && tsc", + "build": "yarn build:rescript && yarn build:typescript", + "build:rescript": "rescript build -with-deps", + "build:typescript": "tsc", "bundle": "webpack", "start": "rescript build -w -with-deps", "clean": "rescript clean && rm -r dist", diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index abb563ed..c4c9b0d3 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -8,15 +8,6 @@ import { externalBindings, expressionValue, errorValue, - distributionError, - toPointSet, - continuousShape, - discreteShape, - distributionErrorToString, - internalCode, - mixedShape, - sampleSetDist, - symbolicDist, } from "../rescript/TypescriptInterface.gen"; export { makeSampleSetDist, @@ -46,48 +37,6 @@ export let defaultSamplingInputs: samplingParams = { xyPointLength: 10000, }; -export type result = - | { - tag: "Ok"; - value: a; - } - | { - tag: "Error"; - value: b; - }; - -export function resultMap( - r: result, - mapFn: (x: a) => b -): result { - if (r.tag === "Ok") { - return { tag: "Ok", value: mapFn(r.value) }; - } else { - return r; - } -} - -function Ok(x: a): result { - return { tag: "Ok", value: x }; -} - -type tagged = { tag: a; value: b }; - -function tag(x: a, y: b): tagged { - return { tag: x, value: y }; -} - -export type squiggleExpression = - | tagged<"symbol", string> - | tagged<"string", string> - | tagged<"call", string> - | tagged<"lambda", [string[], internalCode]> - | tagged<"array", squiggleExpression[]> - | tagged<"boolean", boolean> - | tagged<"distribution", Distribution> - | tagged<"number", number> - | tagged<"record", { [key: string]: squiggleExpression }>; - export function run( squiggleString: string, bindings?: externalBindings, diff --git a/packages/squiggle-lang/src/js/rescript_interop.ts b/packages/squiggle-lang/src/js/rescript_interop.ts index 75c6e733..45f4124b 100644 --- a/packages/squiggle-lang/src/js/rescript_interop.ts +++ b/packages/squiggle-lang/src/js/rescript_interop.ts @@ -5,10 +5,9 @@ import { genericDist, environment, symbolicDist, - recordEV, - internalCode, discreteShape, continuousShape, + lambdaValue, } from "../rescript/TypescriptInterface.gen"; import { Distribution } from "./distribution"; import { tagged, tag } from "./types"; @@ -38,7 +37,7 @@ export type rescriptExport = } | { TAG: 5; // EvLambda - _0: [string[], recordEV, internalCode]; + _0: lambdaValue; } | { TAG: 6; // EvNumber @@ -80,7 +79,7 @@ export type squiggleExpression = | tagged<"symbol", string> | tagged<"string", string> | tagged<"call", string> - | tagged<"lambda", [string[], recordEV, internalCode]> + | tagged<"lambda", lambdaValue> | tagged<"array", squiggleExpression[]> | tagged<"arraystring", string[]> | tagged<"boolean", boolean> diff --git a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res index 0d413bf4..a9151a8f 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res +++ b/packages/squiggle-lang/src/rescript/Distributions/DistributionTypes.res @@ -114,6 +114,7 @@ module DistributionOperation = { | ToFloat(#Mean) => `mean` | ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})` | ToFloat(#Sample) => `sample` + | ToFloat(#IntegralSum) => `integralSum` | ToDist(Normalize) => `normalize` | ToDist(ToPointSet) => `toPointSet` | ToDist(ToSampleSet(r)) => `toSampleSet(${E.I.toString(r)})` diff --git a/packages/squiggle-lang/src/rescript/TypescriptInterface.res b/packages/squiggle-lang/src/rescript/TypescriptInterface.res index 114dc4e6..6ebb8377 100644 --- a/packages/squiggle-lang/src/rescript/TypescriptInterface.res +++ b/packages/squiggle-lang/src/rescript/TypescriptInterface.res @@ -74,7 +74,7 @@ let errorValueToString = Reducer_ErrorValue.errorToString let distributionErrorToString = DistributionTypes.Error.toString @genType -type internalCode = ReducerInterface_ExpressionValue.internalCode +type lambdaValue = ReducerInterface_ExpressionValue.lambdaValue @genType let defaultSamplingEnv = ReducerInterface_GenericDistribution.defaultEnv From 5a0b436932b68673181d73d8373e229d04e97c1c Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 17:52:59 +0200 Subject: [PATCH 45/53] No 666 --- .../Reducer/Reducer_functionTricks_test.res | 22 +++++++++++++++---- .../Reducer_Dispatch_BuiltInMacros.res | 7 +----- .../Reducer_Expression/Reducer_Expression.res | 6 +++-- .../Reducer_Expression_Bindings.res | 3 +++ 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index 1f5b6968..e5808701 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -30,15 +30,29 @@ describe("Arity check", () => { ) }) -describe("function trics", () => { +describe("symbol not defined", () => { testEvalToBe("f(x)=x(y); f(f)", "Error(y is not defined)") testEvalToBe("f(x)=x; f(f)", "Ok(lambda(x=>internal code))") testEvalToBe("f(x)=x(y); f(z)", "Error(z is not defined)") testEvalToBe("f(x)=x(y); f(2)", "Error(2 is not a function)") testEvalToBe("f(x)=x(1); f(2)", "Error(2 is not a function)") - MySkip.testParseToBe("f(x)=f(y)=2; f(2)", "????") - MySkip.testEvalToBe("f(x)=f(y)=2; f(2)", "????") //prevent multiple assignment - testEvalToBe("f(x)=x+1; g(x)=f(x)+1;g(2)", "????") //TODO: f is not found +}) + +Only.describe("call and bindings", () => { + testEvalToBe("f(x)=x+1", "Ok({f: lambda(x=>internal code)})") + testEvalToBe("f(x)=x+1; f(1)", "Ok(2)") + testEvalToBe("f=1;y=2", "Ok({f: 1,y: 2})") + testEvalToBe("f(x)=x+1; y=f(1)", "Ok({f: lambda(x=>internal code),y: 2})") + testEvalToBe("f(x)=x+1; y=f(1); f(1)", "Ok(2)") + testEvalToBe("f(x)=x+1; y=f(1); z=f(1)", "Ok({f: lambda(x=>internal code),y: 2,z: 2})") + testEvalToBe("f(x)=x+1; g(x)=f(x)+1", "Ok({f: lambda(x=>internal code),g: lambda(x=>internal code)})") //TODO: f is not found + MyOnly.testEvalToBe("f(x)=x+1; g(x)=f(x)+1; y=g(2)", "????") //TODO: f is not found + MySkip.testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "????") //TODO: f is not found +}) + +Skip.describe("function trics", () => { + MySkip.testParseToBe("f(x)=f(y)=2; f(2)", "????") // TODO: No multiple assignment + MySkip.testEvalToBe("f(x)=f(y)=2; f(2)", "????") // TODO: No multiple assignment MySkip.testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found MySkip.testEvalToBe("y=2;g(x)=inspect(y)+1", "????") //TODO : 666 }) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index f3f6d8c3..2b6ef13f 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -41,12 +41,7 @@ let dispatchMacroCall = ( let doBindExpression = (bindingExpr: expression, statement: expression, environment) => switch statement { | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { - let rExternalBindingsValue = reduceExpression( - bindingExpr, - Belt.Map.String.fromArray([("x", ExpressionValue.EvNumber(666.))]), - // bindingsToHandDown, - environment, - ) + let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) rExternalBindingsValue->Result.flatMap(externalBindingsValue => { let newBindings = Bindings.fromValue(externalBindingsValue) 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 bb201985..c98da3a8 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 @@ -33,7 +33,9 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en expressionValue, 'e, > => - switch expression { + { + Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`) + switch expression { | T.EValue(value) => value->Ok | T.EList(list) => switch list { @@ -45,7 +47,7 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en } | _ => reduceExpressionList(list, bindings, environment) } - } + }} and reduceExpressionList = ( expressions: list, diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res index 830e93ba..18d17af2 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res @@ -79,3 +79,6 @@ and checkIfCallable = (evValue: expressionValue) => | EvCall(_) | EvLambda(_) => evValue->Ok | _ => ErrorValue.RENotAFunction(ExpressionValue.toString(evValue))->Error } + +let toString = (bindings: ExpressionT.bindings) => + bindings->toExternalBindings->ExpressionValue.EvRecord->ExpressionValue.toString From 6a3b35eb4aa366331a1fd6b413ca717b10a21cb2 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 18:44:35 +0200 Subject: [PATCH 46/53] fixed function f not bound --- .../Reducer/Reducer_TestMacroHelpers.res | 5 +- .../Reducer/Reducer_functionTricks_test.res | 26 ++++-- .../Reducer_Dispatch_BuiltInMacros.res | 85 ++++++++++++++----- .../Reducer_Expression/Reducer_Expression.res | 10 +-- .../Reducer_ExpressionWithContext.res | 45 ++++++++++ .../Reducer_Expression_Bindings.res | 11 +-- .../Reducer_Expression_ExpressionBuilder.res | 8 +- .../Reducer_Expression_Macro.res | 13 ++- 8 files changed, 158 insertions(+), 45 deletions(-) create mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_ExpressionWithContext.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res index af88cac4..330f7da0 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_TestMacroHelpers.res @@ -1,10 +1,11 @@ open Jest open Expect -module Macro = Reducer_Expression_Macro module Bindings = Reducer_Expression_Bindings module Expression = Reducer_Expression module ExpressionValue = ReducerInterface_ExpressionValue +module ExpressionWithContext = Reducer_ExpressionWithContext +module Macro = Reducer_Expression_Macro module T = Reducer_Expression_T let testMacro_ = ( @@ -21,7 +22,7 @@ let testMacro_ = ( ExpressionValue.defaultEnvironment, Expression.reduceExpression, ) - ->T.toStringResult + ->ExpressionWithContext.toStringResult ->expect ->toEqual(expectedCode) ) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index e5808701..f134c309 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -39,15 +39,27 @@ describe("symbol not defined", () => { }) Only.describe("call and bindings", () => { - testEvalToBe("f(x)=x+1", "Ok({f: lambda(x=>internal code)})") - testEvalToBe("f(x)=x+1; f(1)", "Ok(2)") + testEvalToBe("f(x)=x+1", "Ok({f: lambda(x=>internal code)})") + testEvalToBe("f(x)=x+1; f(1)", "Ok(2)") testEvalToBe("f=1;y=2", "Ok({f: 1,y: 2})") - testEvalToBe("f(x)=x+1; y=f(1)", "Ok({f: lambda(x=>internal code),y: 2})") - testEvalToBe("f(x)=x+1; y=f(1); f(1)", "Ok(2)") + testEvalToBe("f(x)=x+1; y=f(1)", "Ok({f: lambda(x=>internal code),y: 2})") + testEvalToBe("f(x)=x+1; y=f(1); f(1)", "Ok(2)") testEvalToBe("f(x)=x+1; y=f(1); z=f(1)", "Ok({f: lambda(x=>internal code),y: 2,z: 2})") - testEvalToBe("f(x)=x+1; g(x)=f(x)+1", "Ok({f: lambda(x=>internal code),g: lambda(x=>internal code)})") //TODO: f is not found - MyOnly.testEvalToBe("f(x)=x+1; g(x)=f(x)+1; y=g(2)", "????") //TODO: f is not found - MySkip.testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "????") //TODO: f is not found + testEvalToBe( + "f(x)=x+1; g(x)=f(x)+1", + "Ok({f: lambda(x=>internal code),g: lambda(x=>internal code)})", + ) + testParseToBe( + "f=99; g(x)=f; g(2)", + "Ok((:$$block (:$$block (:$let :f 99) (:$let :g (:$$lambda [x] (:$$block :f))) (:g 2))))", + ) + testEvalToBe("f=99; g(x)=f; g(2)", "Ok(99)") + testEvalToBe("f(x)=x; g(x)=f(x); g(2)", "Ok(2)") + testEvalToBe( + "f(x)=x+1; g(x)=f(x)+1; y=g(2)", + "Ok({f: lambda(x=>internal code),g: lambda(x=>internal code),y: 4})", + ) + testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "Ok(4)") }) Skip.describe("function trics", () => { diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index 2b6ef13f..c106c0ff 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -6,19 +6,22 @@ module Bindings = Reducer_Expression_Bindings module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface.ExpressionValue +module ExpressionWithContext = Reducer_ExpressionWithContext module Result = Belt.Result open Reducer_Expression_ExpressionBuilder -type expression = ExpressionT.expression type environment = ExpressionValue.environment type errorValue = Reducer_ErrorValue.errorValue +type expression = ExpressionT.expression +type expressionValue = ExpressionValue.expressionValue +type expressionWithContext = ExpressionWithContext.expressionWithContext let dispatchMacroCall = ( macroExpression: expression, bindings: ExpressionT.bindings, environment, reduceExpression: ExpressionT.reducerFn, -): result => { +): result => { let doBindStatement = (bindingExpr: expression, statement: expression, environment) => switch statement { | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { @@ -26,11 +29,23 @@ let dispatchMacroCall = ( rExternalBindingsValue->Result.flatMap(externalBindingsValue => { let newBindings = Bindings.fromValue(externalBindingsValue) + + // Js.log( + // `bindStatement ${Bindings.toString(newBindings)}<==${ExpressionT.toString( + // bindingExpr, + // )} statement: $let ${ExpressionT.toString(symbolExpr)}=${ExpressionT.toString( + // statement, + // )}`, + // ) + let rNewStatement = Bindings.replaceSymbols(newBindings, statement) rNewStatement->Result.map(newStatement => - eFunction( - "$setBindings", - list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement}, + ExpressionWithContext.withContext( + eFunction( + "$setBindings", + list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement}, + ), + newBindings, ) ) }) @@ -38,7 +53,10 @@ let dispatchMacroCall = ( | _ => REAssignmentExpected->Error } - let doBindExpression = (bindingExpr: expression, statement: expression, environment) => + let doBindExpression = (bindingExpr: expression, statement: expression, environment): result< + expressionWithContext, + errorValue, + > => switch statement { | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$let")), symbolExpr, statement}) => { let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) @@ -47,35 +65,49 @@ let dispatchMacroCall = ( let newBindings = Bindings.fromValue(externalBindingsValue) let rNewStatement = Bindings.replaceSymbols(newBindings, statement) rNewStatement->Result.map(newStatement => - eFunction( - "$exportBindings", - list{ - eFunction( - "$setBindings", - list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement}, - ), - }, + ExpressionWithContext.withContext( + eFunction( + "$exportBindings", + list{ + eFunction( + "$setBindings", + list{ + newBindings->Bindings.toExternalBindings->eRecord, + symbolExpr, + newStatement, + }, + ), + }, + ), + newBindings, ) ) }) } | _ => { - let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) + let rExternalBindingsValue: result = reduceExpression( + bindingExpr, + bindings, + environment, + ) + rExternalBindingsValue->Result.flatMap(externalBindingsValue => { let newBindings = Bindings.fromValue(externalBindingsValue) let rNewStatement = Bindings.replaceSymbols(newBindings, statement) - rNewStatement + rNewStatement->Result.map(newStatement => + ExpressionWithContext.withContext(newStatement, newBindings) + ) }) } } let doBlock = (exprs: list, _bindings: ExpressionT.bindings, _environment): result< - expression, + expressionWithContext, errorValue, > => { let exprsArray = Belt.List.toArray(exprs) let maxIndex = Js.Array2.length(exprsArray) - 1 - exprsArray->Js.Array2.reducei((acc, statement, index) => + let newStatement = exprsArray->Js.Array2.reducei((acc, statement, index) => if index == 0 { if index == maxIndex { eBindExpressionDefault(statement) @@ -87,16 +119,23 @@ let dispatchMacroCall = ( } else { eBindStatement(acc, statement) } - , eSymbol("undefined block"))->Ok + , eSymbol("undefined block")) + ExpressionWithContext.noContext(newStatement)->Ok } let doLambdaDefinition = ( bindings: ExpressionT.bindings, parameters: array, lambdaDefinition: ExpressionT.expression, - ) => eLambda(parameters, bindings->Bindings.toExternalBindings, lambdaDefinition)->Ok + ) => + ExpressionWithContext.noContext( + eLambda(parameters, bindings->Bindings.toExternalBindings, lambdaDefinition), + )->Ok - let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment) => + let expandExpressionList = (aList, bindings: ExpressionT.bindings, environment): result< + expressionWithContext, + errorValue, + > => switch aList { | list{ ExpressionT.EValue(EvCall("$$bindStatement")), @@ -123,11 +162,11 @@ let dispatchMacroCall = ( lambdaDefinition, } => doLambdaDefinition(bindings, parameters, lambdaDefinition) - | _ => ExpressionT.EList(aList)->Ok + | _ => ExpressionWithContext.noContext(ExpressionT.EList(aList))->Ok } switch macroExpression { | EList(aList) => expandExpressionList(aList, bindings, environment) - | _ => macroExpression->Ok + | _ => ExpressionWithContext.noContext(macroExpression)->Ok } } 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 c98da3a8..e1df1418 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 @@ -32,10 +32,9 @@ let parse = (mathJsCode: string): result => let rec reduceExpression = (expression: t, bindings: T.bindings, environment: environment): result< expressionValue, 'e, -> => - { - Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`) - switch expression { +> => { + // Js.log(`reduce: ${T.toString(expression)} bindings: ${bindings->Bindings.toString}`) + switch expression { | T.EValue(value) => value->Ok | T.EList(list) => switch list { @@ -47,7 +46,8 @@ let rec reduceExpression = (expression: t, bindings: T.bindings, environment: en } | _ => reduceExpressionList(list, bindings, environment) } - }} + } +} and reduceExpressionList = ( expressions: list, diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_ExpressionWithContext.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_ExpressionWithContext.res new file mode 100644 index 00000000..dacd2462 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_ExpressionWithContext.res @@ -0,0 +1,45 @@ +module Bindings = Reducer_Expression_Bindings +module ErrorValue = Reducer_ErrorValue +module ExpressionT = Reducer_Expression_T +module ExpressionValue = ReducerInterface.ExpressionValue +module Result = Belt.Result + +type bindings = ExpressionT.bindings +type context = bindings +type environment = ExpressionValue.environment +type errorValue = Reducer_ErrorValue.errorValue +type expression = ExpressionT.expression +type expressionValue = ExpressionValue.expressionValue +type externalBindings = ReducerInterface_ExpressionValue.externalBindings +type reducerFn = ExpressionT.reducerFn + +type expressionWithContext = + | ExpressionWithContext(expression, context) + | ExpressionNoContext(expression) + +let callReducer = ( + expressionWithContext: expressionWithContext, + bindings: bindings, + environment: environment, + reducer: reducerFn, +): result => + switch expressionWithContext { + | ExpressionNoContext(expr) => reducer(expr, bindings, environment) + | ExpressionWithContext(expr, context) => reducer(expr, context, environment) + } + +let withContext = (expression, context) => ExpressionWithContext(expression, context) +let noContext = expression => ExpressionNoContext(expression) + +let toString = expressionWithContext => + switch expressionWithContext { + | ExpressionNoContext(expr) => ExpressionT.toString(expr) + | ExpressionWithContext(expr, context) => + `${ExpressionT.toString(expr)} context: ${Bindings.toString(context)}` + } + +let toStringResult = rExpressionWithContext => + switch rExpressionWithContext { + | Ok(expressionWithContext) => `Ok(${toString(expressionWithContext)})` + | Error(errorValue) => ErrorValue.errorToString(errorValue) + } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res index 18d17af2..7c0c048a 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res @@ -68,10 +68,8 @@ and replaceSymbolsOnExpressionList = (bindings, list) => { } and replaceSymbolOnValue = (bindings, evValue: expressionValue) => switch evValue { - | EvSymbol(symbol) => - Belt.Map.String.getWithDefault(bindings, symbol, evValue)->Ok - | EvCall(symbol) => - Belt.Map.String.getWithDefault(bindings, symbol, evValue)->checkIfCallable + | EvSymbol(symbol) => Belt.Map.String.getWithDefault(bindings, symbol, evValue)->Ok + | EvCall(symbol) => Belt.Map.String.getWithDefault(bindings, symbol, evValue)->checkIfCallable | _ => evValue->Ok } and checkIfCallable = (evValue: expressionValue) => @@ -80,5 +78,8 @@ and checkIfCallable = (evValue: expressionValue) => | _ => ErrorValue.RENotAFunction(ExpressionValue.toString(evValue))->Error } -let toString = (bindings: ExpressionT.bindings) => +let toString = (bindings: ExpressionT.bindings) => bindings->toExternalBindings->ExpressionValue.EvRecord->ExpressionValue.toString + +let externalBindingsToString = (externalBindings: externalBindings) => + externalBindings->ExpressionValue.EvRecord->ExpressionValue.toString diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res index 3aa0fcba..9c9f922e 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res @@ -25,12 +25,18 @@ let eFunction = (fName: string, lispArgs: list): expression => { list{fn, ...lispArgs}->BExpressionT.EList } -let eLambda = (parameters: array, context, expr) => +let eLambda = ( + parameters: array, + context: BExpressionValue.externalBindings, + expr: expression, +) => { + // Js.log(`eLambda context ${BBindings.externalBindingsToString(context)}`) BExpressionValue.EvLambda({ parameters: parameters, context: context, body: expr->castExpressionToInternalCode, })->BExpressionT.EValue +} let eNumber = aNumber => aNumber->BExpressionValue.EvNumber->BExpressionT.EValue diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res index 5ac19502..23fb70f8 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Macro.res @@ -1,17 +1,19 @@ module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface.ExpressionValue +module ExpressionWithContext = Reducer_ExpressionWithContext module Result = Belt.Result type environment = ExpressionValue.environment type expression = ExpressionT.expression type expressionValue = ExpressionValue.expressionValue +type expressionWithContext = ExpressionWithContext.expressionWithContext let expandMacroCall = ( macroExpression: expression, bindings: ExpressionT.bindings, environment: environment, reduceExpression: ExpressionT.reducerFn, -): result => +): result => Reducer_Dispatch_BuiltInMacros.dispatchMacroCall( macroExpression, bindings, @@ -30,6 +32,13 @@ let doMacroCall = ( bindings, environment, reduceExpression, - )->Result.flatMap(expression => reduceExpression(expression, bindings, environment)) + )->Result.flatMap(expressionWithContext => + ExpressionWithContext.callReducer( + expressionWithContext, + bindings, + environment, + reduceExpression, + ) + ) let isMacroName = (fName: string): bool => fName->Js.String2.startsWith("$$") From 490e4908e171627a88ae752de7181685858a8bb4 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 23:18:36 +0200 Subject: [PATCH 47/53] sam's monkeying --- .../Reducer/Reducer_functionTricks_test.res | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index f134c309..b425c88e 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -38,7 +38,7 @@ describe("symbol not defined", () => { testEvalToBe("f(x)=x(1); f(2)", "Error(2 is not a function)") }) -Only.describe("call and bindings", () => { +describe("call and bindings", () => { testEvalToBe("f(x)=x+1", "Ok({f: lambda(x=>internal code)})") testEvalToBe("f(x)=x+1; f(1)", "Ok(2)") testEvalToBe("f=1;y=2", "Ok({f: 1,y: 2})") @@ -62,9 +62,11 @@ Only.describe("call and bindings", () => { testEvalToBe("f(x)=x+1; g(x)=f(x)+1; g(2)", "Ok(4)") }) -Skip.describe("function trics", () => { - MySkip.testParseToBe("f(x)=f(y)=2; f(2)", "????") // TODO: No multiple assignment - MySkip.testEvalToBe("f(x)=f(y)=2; f(2)", "????") // TODO: No multiple assignment - MySkip.testEvalToBe("y=2;g(x)=y+1;g(2)", "????") //TODO : y is not found - MySkip.testEvalToBe("y=2;g(x)=inspect(y)+1", "????") //TODO : 666 +describe("function trics", () => { + testParseToBe( + "f(x)=f(y)=2; f(2)", + "Ok((:$$block (:$$block (:$let :f (:$$lambda [x] (:$$block (:$let :f (:$$lambda [y] (:$$block 2)))))) (:f 2))))") + testEvalToBe("f(x)=f(y)=2; f(2)","Ok({f: lambda(y=>internal code),x: 2})") + testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)") + testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})") }) From 11d4a3bc8be0bd152f783b8aad2d9071c6d30e3b Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 2 May 2022 23:42:11 +0200 Subject: [PATCH 48/53] do not export private modules from Reducer module --- .../Reducer_MathJs/Reducer_MathJsEval_test.res | 2 +- .../Reducer_MathJs/Reducer_MathJsParse_test.res | 2 +- .../__tests__/Reducer/Reducer_functionTricks_test.res | 11 ++++++----- .../squiggle-lang/src/rescript/Reducer/Reducer.res | 4 ---- .../squiggle-lang/src/rescript/Reducer/Reducer.resi | 4 ---- 5 files changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res index 355c69ea..6f232d0e 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_MathJs/Reducer_MathJsEval_test.res @@ -1,5 +1,5 @@ open ReducerInterface.ExpressionValue -module MathJs = Reducer.MathJs +module MathJs = Reducer_MathJs module ErrorValue = Reducer.ErrorValue open Jest 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 a79ff024..b085eeb3 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 @@ -1,4 +1,4 @@ -module Parse = Reducer.MathJs.Parse +module Parse = Reducer_MathJs.Parse module Result = Belt.Result open Jest diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index b425c88e..9ca8304d 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -64,9 +64,10 @@ describe("call and bindings", () => { describe("function trics", () => { testParseToBe( - "f(x)=f(y)=2; f(2)", - "Ok((:$$block (:$$block (:$let :f (:$$lambda [x] (:$$block (:$let :f (:$$lambda [y] (:$$block 2)))))) (:f 2))))") - testEvalToBe("f(x)=f(y)=2; f(2)","Ok({f: lambda(y=>internal code),x: 2})") - testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)") - testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})") + "f(x)=f(y)=2; f(2)", + "Ok((:$$block (:$$block (:$let :f (:$$lambda [x] (:$$block (:$let :f (:$$lambda [y] (:$$block 2)))))) (:f 2))))", + ) + testEvalToBe("f(x)=f(y)=2; f(2)", "Ok({f: lambda(y=>internal code),x: 2})") + testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)") + testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})") }) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res index 24c985d8..1ee57529 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.res @@ -1,9 +1,5 @@ -module Dispatch = Reducer_Dispatch module ErrorValue = Reducer_ErrorValue module Expression = Reducer_Expression -module Extra = Reducer_Extra -module Js = Reducer_Js -module MathJs = Reducer_MathJs type environment = ReducerInterface_ExpressionValue.environment type errorValue = Reducer_ErrorValue.errorValue diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi index 4e86361a..71b394fb 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer.resi @@ -1,9 +1,5 @@ -module Dispatch = Reducer_Dispatch module ErrorValue = Reducer_ErrorValue module Expression = Reducer_Expression -module Extra = Reducer_Extra -module Js = Reducer_Js -module MathJs = Reducer_MathJs @genType type environment = ReducerInterface_ExpressionValue.environment From 6e72b89f7f878f34312cd70b254e4013f7cfd8b3 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Mon, 2 May 2022 21:59:56 +0000 Subject: [PATCH 49/53] Add array string and function viewers --- packages/components/src/components/SquiggleChart.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/components/src/components/SquiggleChart.tsx b/packages/components/src/components/SquiggleChart.tsx index 3210b1d8..887b792b 100644 --- a/packages/components/src/components/SquiggleChart.tsx +++ b/packages/components/src/components/SquiggleChart.tsx @@ -156,6 +156,18 @@ const SquiggleItem: React.FC = ({ ))} ); + case "arraystring": + return ( + + {expression.value.map((r) => `"${r}"`)} + + ); + case "lambda": + return ( + + There is no viewer currently available for function types. + + ); } }; From d26eaa2523d88b52c019d431433884d548a0e8f7 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 3 May 2022 00:16:29 +0200 Subject: [PATCH 50/53] Note infinite recursion --- .../__tests__/Reducer/Reducer_functionTricks_test.res | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index 9ca8304d..208c3085 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -70,4 +70,5 @@ describe("function trics", () => { testEvalToBe("f(x)=f(y)=2; f(2)", "Ok({f: lambda(y=>internal code),x: 2})") testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)") testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})") + //testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout? }) From 78f46daed8ce7d03c23a8b23fd50c0bf1d230a64 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 3 May 2022 00:18:23 +0200 Subject: [PATCH 51/53] Note infinite recursion --- .../__tests__/Reducer/Reducer_functionTricks_test.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index 208c3085..d7040910 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -70,5 +70,5 @@ describe("function trics", () => { testEvalToBe("f(x)=f(y)=2; f(2)", "Ok({f: lambda(y=>internal code),x: 2})") testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)") testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})") - //testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout? + MySkip.testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout? }) From c5ae846df4559a31ff31d639f1eed9edb7898de4 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 3 May 2022 00:30:41 +0200 Subject: [PATCH 52/53] Note duplicate parameters --- .../__tests__/Reducer/Reducer_functionTricks_test.res | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index d7040910..0d2ed4c5 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -71,4 +71,5 @@ describe("function trics", () => { testEvalToBe("y=2;g(x)=y+1;g(2)", "Ok(3)") testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})") MySkip.testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout? + MySkip.testEvalToBe("f(x, x)=x+x; f(1,2)", "????") // TODO: Duplicate parameters }) From 88428c74afa8b2ec48b4dd569fbc98e8792e0109 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Tue, 3 May 2022 00:38:40 +0200 Subject: [PATCH 53/53] cases to handle with new parser. lambdas in arrays and records --- .../__tests__/Reducer/Reducer_functionTricks_test.res | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res index 0d2ed4c5..284364e6 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_functionTricks_test.res @@ -72,4 +72,6 @@ describe("function trics", () => { testEvalToBe("y=2;g(x)=inspect(y)+1", "Ok({g: lambda(x=>internal code),y: 2})") MySkip.testEvalToBe("f(x) = x(x); f(f)", "????") // TODO: Infinite loop. Any solution? Catching proper exception or timeout? MySkip.testEvalToBe("f(x, x)=x+x; f(1,2)", "????") // TODO: Duplicate parameters + MySkip.testEvalToBe("myadd(x,y)=x+y; z=[add]; z[0](3,2)", "????") //TODO: to fix with new parser + MySkip.testEvalToBe("myaddd(x,y)=x+y; z={x: add}; z.x(3,2)", "????") //TODO: to fix with new parser })