From 33ee0b27d50cf8dfcfb067ae0a613c760a7e16bc Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Wed, 4 May 2022 15:14:34 +0200 Subject: [PATCH 1/3] remove inspect performance completely Redesign required on the function interface --- .../Reducer/Reducer_debugging_test.res | 1 - .../Reducer_Dispatch_BuiltIn.res | 38 ++++++++----------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res index f005c1fc..51efdbea 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_debugging_test.res @@ -12,5 +12,4 @@ open Reducer_TestHelpers describe("Debugging", () => { testEvalToBe("inspect(1)", "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 25fc05a7..b8630a6a 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,6 +1,7 @@ module ExternalLibrary = ReducerInterface.ExternalLibrary module MathJs = Reducer_MathJs module Bindings = Reducer_Expression_Bindings +module Lambda = Reducer_Expression_Lambda open ReducerInterface.ExpressionValue open Reducer_ErrorValue @@ -54,21 +55,6 @@ let callInternal = (call: functionCall, _environment): 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()`) - // 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 - } - let doSetBindings = ( externalBindings: externalBindings, symbol: string, @@ -83,19 +69,25 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> => let doExportBindings = (externalBindings: externalBindings) => EvRecord(externalBindings)->Ok + // let doMapArray = (aValueArray, aLambdaValue) => { + // aValueArray->Belt.Array.reduceReverse( + // Ok(list{}), + // (rAcc, elem) => R + // ) + // } + // let doReduceArray(aValueArray, initialValue, aLambdaValue) + switch call { - | ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) => - arrayAtIndex(aValueArray, fIndex) + // | ("$atIndex", [obj, index]) => (toStringWithType(obj) ++ "??~~~~" ++ toStringWithType(index))->EvString->Ok + | ("$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) + | ("$exportBindings", [EvRecord(externalBindings)]) => doExportBindings(externalBindings) + | ("$setBindings", [EvRecord(externalBindings), EvSymbol(symbol), value]) => doSetBindings(externalBindings, symbol, value) | ("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) + // | ("map", [EvArray(aValueArray), EvLambda(lambdaValue)]) => doMapArray(aValueArray, aLambdaValue) + // | ("reduce", [EvArray(aValueArray), initialValue, EvLambda(lambdaValue)]) => doReduceArray(aValueArray, initialValue, aLambdaValue) | call => callMathJs(call) } } From ae48bd642002595c8cbd1fe818c0752d919ca9e2 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Wed, 4 May 2022 15:22:28 +0200 Subject: [PATCH 2/3] pass reducer to dispatch to define functions that has lambda arguments, dispatching requires a reducer --- .../Reducer_Dispatch_BuiltIn.res | 24 +++++++++++++------ .../Reducer_Expression/Reducer_Expression.res | 3 ++- .../Reducer_Expression_Lambda.res | 3 +-- 3 files changed, 20 insertions(+), 10 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 b8630a6a..60f31c89 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,7 +1,8 @@ -module ExternalLibrary = ReducerInterface.ExternalLibrary -module MathJs = Reducer_MathJs module Bindings = Reducer_Expression_Bindings +module ExpressionT = Reducer_Expression_T +module ExternalLibrary = ReducerInterface.ExternalLibrary module Lambda = Reducer_Expression_Lambda +module MathJs = Reducer_MathJs open ReducerInterface.ExpressionValue open Reducer_ErrorValue @@ -13,7 +14,10 @@ open Reducer_ErrorValue exception TestRescriptException -let callInternal = (call: functionCall, _environment): result<'b, errorValue> => { +let callInternal = (call: functionCall, _environment, _reducer: ExpressionT.reducerFn): result< + 'b, + errorValue, +> => { let callMathJs = (call: functionCall): result<'b, errorValue> => switch call { | ("javascriptraise", [msg]) => Js.Exn.raiseError(toString(msg)) // For Tests @@ -79,11 +83,13 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> => switch call { // | ("$atIndex", [obj, index]) => (toStringWithType(obj) ++ "??~~~~" ++ toStringWithType(index))->EvString->Ok - | ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) => arrayAtIndex(aValueArray, fIndex) + | ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) => + arrayAtIndex(aValueArray, fIndex) | ("$atIndex", [EvRecord(dict), EvArray([EvString(sIndex)])]) => recordAtIndex(dict, sIndex) | ("$constructRecord", [EvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs) | ("$exportBindings", [EvRecord(externalBindings)]) => doExportBindings(externalBindings) - | ("$setBindings", [EvRecord(externalBindings), EvSymbol(symbol), value]) => doSetBindings(externalBindings, symbol, value) + | ("$setBindings", [EvRecord(externalBindings), EvSymbol(symbol), value]) => + doSetBindings(externalBindings, symbol, value) | ("inspect", [value, EvString(label)]) => inspectLabel(value, label) | ("inspect", [value]) => inspect(value) // | ("map", [EvArray(aValueArray), EvLambda(lambdaValue)]) => doMapArray(aValueArray, aLambdaValue) @@ -95,12 +101,16 @@ let callInternal = (call: functionCall, _environment): result<'b, errorValue> => /* Reducer uses Result monad while reducing expressions */ -let dispatch = (call: functionCall, environment): result => +let dispatch = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result< + expressionValue, + errorValue, +> => try { + let callInternalWithReducer = (call, environment) => callInternal(call, environment, reducer) 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), environment, callInternal) + ExternalLibrary.dispatch((Js.String.make(fn), args), environment, callInternalWithReducer) } 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_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index e1df1418..81830e84 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 @@ -77,7 +77,8 @@ and reduceValueList = (valueList: list, environment): result< '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, reduceExpression) | list{EvLambda(lamdaCall), ...args} => Lambda.doLambdaCall(lamdaCall, args, environment, reduceExpression) 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 55931cc7..35546465 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 @@ -55,6 +55,5 @@ let applyParametersToLambda = ( ) } -let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) => { +let doLambdaCall = (lambdaValue: ExpressionValue.lambdaValue, args, environment, reducer) => applyParametersToLambda(lambdaValue, args, environment, reducer) -} From 5de6aa8e0d1590d787eb50eacf1454cfd8e3b4cf Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Wed, 4 May 2022 15:46:00 +0200 Subject: [PATCH 3/3] map reduce reduceReverse reverse keep --- .../Reducer/Reducer_mapReduce_test.res | 11 ++++ .../Reducer_Dispatch_BuiltIn.res | 61 +++++++++++++++---- 2 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_mapReduce_test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_mapReduce_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_mapReduce_test.res new file mode 100644 index 00000000..674012be --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_mapReduce_test.res @@ -0,0 +1,11 @@ +open Jest +open Reducer_TestHelpers + +describe("map reduce", () => { + testEvalToBe("double(x)=2*x; arr=[1,2,3]; map(arr, double)", "Ok([2,4,6])") + testEvalToBe("myadd(acc,x)=acc+x; arr=[1,2,3]; reduce(arr, 0, myadd)", "Ok(6)") + testEvalToBe("change(acc,x)=acc*x+x; arr=[1,2,3]; reduce(arr, 0, change)", "Ok(15)") + testEvalToBe("change(acc,x)=acc*x+x; arr=[1,2,3]; reduceReverse(arr, 0, change)", "Ok(9)") + testEvalToBe("arr=[1,2,3]; reverse(arr)", "Ok([3,2,1])") + testEvalToBe("check(x)=(x==2);arr=[1,2,3]; keep(arr,check)", "Ok([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 60f31c89..d1a77040 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 @@ -3,6 +3,7 @@ module ExpressionT = Reducer_Expression_T module ExternalLibrary = ReducerInterface.ExternalLibrary module Lambda = Reducer_Expression_Lambda module MathJs = Reducer_MathJs +module Result = Belt.Result open ReducerInterface.ExpressionValue open Reducer_ErrorValue @@ -14,7 +15,7 @@ open Reducer_ErrorValue exception TestRescriptException -let callInternal = (call: functionCall, _environment, _reducer: ExpressionT.reducerFn): result< +let callInternal = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result< 'b, errorValue, > => { @@ -73,16 +74,48 @@ let callInternal = (call: functionCall, _environment, _reducer: ExpressionT.redu let doExportBindings = (externalBindings: externalBindings) => EvRecord(externalBindings)->Ok - // let doMapArray = (aValueArray, aLambdaValue) => { - // aValueArray->Belt.Array.reduceReverse( - // Ok(list{}), - // (rAcc, elem) => R - // ) - // } - // let doReduceArray(aValueArray, initialValue, aLambdaValue) + let doKeepArray = (aValueArray, aLambdaValue) => { + let rMappedList = aValueArray->Belt.Array.reduceReverse(Ok(list{}), (rAcc, elem) => + rAcc->Result.flatMap(acc => { + let rNewElem = Lambda.doLambdaCall(aLambdaValue, list{elem}, environment, reducer) + rNewElem->Result.map(newElem => + switch newElem { + | EvBool(true) => list{elem, ...acc} + | _ => acc + } + ) + }) + ) + rMappedList->Result.map(mappedList => mappedList->Belt.List.toArray->EvArray) + } + + let doMapArray = (aValueArray, aLambdaValue) => { + let rMappedList = aValueArray->Belt.Array.reduceReverse(Ok(list{}), (rAcc, elem) => + rAcc->Result.flatMap(acc => { + let rNewElem = Lambda.doLambdaCall(aLambdaValue, list{elem}, environment, reducer) + rNewElem->Result.map(newElem => list{newElem, ...acc}) + }) + ) + rMappedList->Result.map(mappedList => mappedList->Belt.List.toArray->EvArray) + } + + let doReduceArray = (aValueArray, initialValue, aLambdaValue) => { + aValueArray->Belt.Array.reduce(Ok(initialValue), (rAcc, elem) => + rAcc->Result.flatMap(acc => + Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, environment, reducer) + ) + ) + } + + let doReduceReverseArray = (aValueArray, initialValue, aLambdaValue) => { + aValueArray->Belt.Array.reduceReverse(Ok(initialValue), (rAcc, elem) => + rAcc->Result.flatMap(acc => + Lambda.doLambdaCall(aLambdaValue, list{acc, elem}, environment, reducer) + ) + ) + } switch call { - // | ("$atIndex", [obj, index]) => (toStringWithType(obj) ++ "??~~~~" ++ toStringWithType(index))->EvString->Ok | ("$atIndex", [EvArray(aValueArray), EvArray([EvNumber(fIndex)])]) => arrayAtIndex(aValueArray, fIndex) | ("$atIndex", [EvRecord(dict), EvArray([EvString(sIndex)])]) => recordAtIndex(dict, sIndex) @@ -92,8 +125,14 @@ let callInternal = (call: functionCall, _environment, _reducer: ExpressionT.redu doSetBindings(externalBindings, symbol, value) | ("inspect", [value, EvString(label)]) => inspectLabel(value, label) | ("inspect", [value]) => inspect(value) - // | ("map", [EvArray(aValueArray), EvLambda(lambdaValue)]) => doMapArray(aValueArray, aLambdaValue) - // | ("reduce", [EvArray(aValueArray), initialValue, EvLambda(lambdaValue)]) => doReduceArray(aValueArray, initialValue, aLambdaValue) + | ("keep", [EvArray(aValueArray), EvLambda(aLambdaValue)]) => + doKeepArray(aValueArray, aLambdaValue) + | ("map", [EvArray(aValueArray), EvLambda(aLambdaValue)]) => doMapArray(aValueArray, aLambdaValue) + | ("reduce", [EvArray(aValueArray), initialValue, EvLambda(aLambdaValue)]) => + doReduceArray(aValueArray, initialValue, aLambdaValue) + | ("reduceReverse", [EvArray(aValueArray), initialValue, EvLambda(aLambdaValue)]) => + doReduceReverseArray(aValueArray, initialValue, aLambdaValue) + | ("reverse", [EvArray(aValueArray)]) => aValueArray->Belt.Array.reverse->EvArray->Ok | call => callMathJs(call) } }