From 9f0e4f34fe7dcf0ed75d87f5f8139c747b69d144 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 7 Jul 2022 12:01:02 -0700 Subject: [PATCH 01/40] First attempt at integrating namespaces --- .../FunctionRegistry_Core.res | 6 +- .../FunctionRegistry_Helpers.res | 59 +++-- .../FunctionRegistry_Library.res | 230 +++++++++++------- 3 files changed, 190 insertions(+), 105 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index bbca7bc7..be94ea99 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -39,6 +39,8 @@ and frValueDictParam = (string, frValue) and frValueDistOrNumber = FRValueNumber(float) | FRValueDist(DistributionTypes.genericDist) type fnDefinition = { + nameSpace: option, + requiresNamespace: bool, name: string, inputs: array, run: (array, DistributionOperation.env) => result, @@ -327,8 +329,10 @@ module FnDefinition = { } } - let make = (~name, ~inputs, ~run): t => { + let make = (~nameSpace=None, ~requiresNamespace=true, ~name, ~inputs, ~run, ()): t => { name: name, + nameSpace: nameSpace, + requiresNamespace: requiresNamespace, inputs: inputs, run: run, } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res index 46ae18f9..1a42cb50 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -201,8 +201,11 @@ module TwoArgDist = { ->E.R2.fmap(Wrappers.evDistribution) let make = (name, fn) => { - FnDefinition.make(~name, ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], ~run=(inputs, env) => - inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env) + FnDefinition.make( + ~name, + ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], + ~run=(inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), + (), ) } @@ -211,6 +214,7 @@ module TwoArgDist = { ~name, ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], ~run=(inputs, env) => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), + (), ) } @@ -219,6 +223,7 @@ module TwoArgDist = { ~name, ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], ~run=(inputs, env) => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), + (), ) } } @@ -230,35 +235,51 @@ module OneArgDist = { ->E.R2.fmap(Wrappers.evDistribution) let make = (name, fn) => - FnDefinition.make(~name, ~inputs=[FRTypeDistOrNumber], ~run=(inputs, env) => - inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env) + FnDefinition.make( + ~name, + ~inputs=[FRTypeDistOrNumber], + ~run=(inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), + (), ) } module ArrayNumberDist = { let make = (name, fn) => { - FnDefinition.make(~name, ~inputs=[FRTypeArray(FRTypeNumber)], ~run=(inputs, _) => - Prepare.ToTypedArray.numbers(inputs) - ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) - ->E.R.bind(fn) + FnDefinition.make( + ~name, + ~inputs=[FRTypeArray(FRTypeNumber)], + ~run=(inputs, _) => + Prepare.ToTypedArray.numbers(inputs) + ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) + ->E.R.bind(fn), + (), ) } let make2 = (name, fn) => { - FnDefinition.make(~name, ~inputs=[FRTypeArray(FRTypeAny)], ~run=(inputs, _) => - Prepare.ToTypedArray.numbers(inputs) - ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) - ->E.R.bind(fn) + FnDefinition.make( + ~name, + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _) => + Prepare.ToTypedArray.numbers(inputs) + ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) + ->E.R.bind(fn), + (), ) } } module NumberToNumber = { let make = (name, fn) => - FnDefinition.make(~name, ~inputs=[FRTypeNumber], ~run=(inputs, _) => { - inputs - ->getOrError(0) - ->E.R.bind(Prepare.oneNumber) - ->E.R2.fmap(fn) - ->E.R2.fmap(Wrappers.evNumber) - }) + FnDefinition.make( + ~name, + ~inputs=[FRTypeNumber], + ~run=(inputs, _) => { + inputs + ->getOrError(0) + ->E.R.bind(Prepare.oneNumber) + ->E.R2.fmap(fn) + ->E.R2.fmap(Wrappers.evNumber) + }, + (), + ) } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index a37b8dc4..780356dc 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -54,9 +54,12 @@ let registry = [ ~name="toContinuousPointSet", ~definitions=[ FnDefinition.make( - ~name="toContinuousPointSet", + ~nameSpace=Some("PointSet"), + ~requiresNamespace=true, + ~name="makeContinuous", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], ~run=(inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), + (), ), ], (), @@ -65,9 +68,12 @@ let registry = [ ~name="toDiscretePointSet", ~definitions=[ FnDefinition.make( - ~name="toDiscretePointSet", + ~nameSpace=Some("PointSet"), + ~requiresNamespace=true, + ~name="makeDiscrete", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), + ~run=(inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), + (), ), ], (), @@ -75,9 +81,14 @@ let registry = [ Function.make( ~name="Declaration", ~definitions=[ - FnDefinition.make(~name="declareFn", ~inputs=[Declaration.frType], ~run=(inputs, _) => { - inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue) - }), + FnDefinition.make( + ~name="declareFn", + ~inputs=[Declaration.frType], + ~run=(inputs, _) => { + inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue) + }, + (), + ), ], (), ), @@ -189,6 +200,7 @@ to(5,10) ~name="toContinuousPointSet", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], ~run=(inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), + (), ), ], (), @@ -207,6 +219,7 @@ to(5,10) ~name="toDiscretePointSet", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], ~run=(inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), + (), ), ], (), @@ -222,9 +235,14 @@ to(5,10) ] })`, ~definitions=[ - FnDefinition.make(~name="declareFn", ~inputs=[Declaration.frType], ~run=(inputs, _) => { - inputs->E.A.unsafe_get(0)->Declaration.fromExpressionValue - }), + FnDefinition.make( + ~name="declareFn", + ~inputs=[Declaration.frType], + ~run=(inputs, _) => { + inputs->E.A.unsafe_get(0)->Declaration.fromExpressionValue + }, + (), + ), ], ~isExperimental=true, (), @@ -366,6 +384,8 @@ to(5,10) ~name="Dict.merge", ~definitions=[ FnDefinition.make( + ~nameSpace=Some("Dict"), + ~requiresNamespace=true, ~name="merge", ~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)], ~run=(inputs, _) => { @@ -380,6 +400,7 @@ to(5,10) | _ => Error(impossibleError) } }, + (), ), ], (), @@ -388,16 +409,19 @@ to(5,10) Function.make( ~name="Dict.mergeMany", ~definitions=[ - FnDefinition.make(~name="mergeMany", ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], ~run=( - inputs, - _, - ) => - inputs - ->Prepare.ToTypedArray.dicts - ->E.R2.fmap(E.Dict.concatMany) - ->E.R2.fmap(Js.Dict.map((. r) => FunctionRegistry_Core.FRType.matchReverse(r))) - ->E.R2.fmap(r => r->Js.Dict.entries->Belt.Map.String.fromArray) - ->E.R2.fmap(Wrappers.evRecord) + FnDefinition.make( + ~nameSpace=Some("Dict"), + ~requiresNamespace=true, + ~name="mergeMany", + ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], + ~run=(inputs, _) => + inputs + ->Prepare.ToTypedArray.dicts + ->E.R2.fmap(E.Dict.concatMany) + ->E.R2.fmap(Js.Dict.map((. r) => FunctionRegistry_Core.FRType.matchReverse(r))) + ->E.R2.fmap(r => r->Js.Dict.entries->Belt.Map.String.fromArray) + ->E.R2.fmap(Wrappers.evRecord), + (), ), ], (), @@ -405,11 +429,18 @@ to(5,10) Function.make( ~name="Dict.keys", ~definitions=[ - FnDefinition.make(~name="keys", ~inputs=[FRTypeDict(FRTypeAny)], ~run=(inputs, _) => - switch inputs { - | [FRValueDict(d1)] => Js.Dict.keys(d1)->E.A2.fmap(Wrappers.evString)->Wrappers.evArray->Ok - | _ => Error(impossibleError) - } + FnDefinition.make( + ~nameSpace=Some("Dict"), + ~requiresNamespace=true, + ~name="keys", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _) => + switch inputs { + | [FRValueDict(d1)] => + Js.Dict.keys(d1)->E.A2.fmap(Wrappers.evString)->Wrappers.evArray->Ok + | _ => Error(impossibleError) + }, + (), ), ], (), @@ -417,15 +448,21 @@ to(5,10) Function.make( ~name="Dict.values", ~definitions=[ - FnDefinition.make(~name="values", ~inputs=[FRTypeDict(FRTypeAny)], ~run=(inputs, _) => - switch inputs { - | [FRValueDict(d1)] => - Js.Dict.values(d1) - ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) - ->Wrappers.evArray - ->Ok - | _ => Error(impossibleError) - } + FnDefinition.make( + ~nameSpace=Some("Dict"), + ~requiresNamespace=true, + ~name="values", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _) => + switch inputs { + | [FRValueDict(d1)] => + Js.Dict.values(d1) + ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) + ->Wrappers.evArray + ->Ok + | _ => Error(impossibleError) + }, + (), ), ], (), @@ -433,21 +470,27 @@ to(5,10) Function.make( ~name="Dict.toList", ~definitions=[ - FnDefinition.make(~name="dictToList", ~inputs=[FRTypeDict(FRTypeAny)], ~run=(inputs, _) => - switch inputs { - | [FRValueDict(dict)] => - dict - ->Js.Dict.entries - ->E.A2.fmap(((key, value)) => - Wrappers.evArray([ - Wrappers.evString(key), - FunctionRegistry_Core.FRType.matchReverse(value), - ]) - ) - ->Wrappers.evArray - ->Ok - | _ => Error(impossibleError) - } + FnDefinition.make( + ~nameSpace=Some("Dict"), + ~requiresNamespace=true, + ~name="toList", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _) => + switch inputs { + | [FRValueDict(dict)] => + dict + ->Js.Dict.entries + ->E.A2.fmap(((key, value)) => + Wrappers.evArray([ + Wrappers.evString(key), + FunctionRegistry_Core.FRType.matchReverse(value), + ]) + ) + ->Wrappers.evArray + ->Ok + | _ => Error(impossibleError) + }, + (), ), ], (), @@ -455,25 +498,29 @@ to(5,10) Function.make( ~name="Dict.fromList", ~definitions=[ - FnDefinition.make(~name="dictFromList", ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], ~run=( - inputs, - _, - ) => { - let convertInternalItems = items => - items - ->E.A2.fmap(item => { - switch item { - | [FRValueString(string), value] => - (string, FunctionRegistry_Core.FRType.matchReverse(value))->Ok - | _ => Error(impossibleError) - } - }) - ->E.A.R.firstErrorOrOpen - ->E.R2.fmap(Belt.Map.String.fromArray) - ->E.R2.fmap(Wrappers.evRecord) - inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.arrayOfArrays) - |> E.R2.bind(convertInternalItems) - }), + FnDefinition.make( + ~nameSpace=Some("Dict"), + ~requiresNamespace=true, + ~name="fromList", + ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], + ~run=(inputs, _) => { + let convertInternalItems = items => + items + ->E.A2.fmap(item => { + switch item { + | [FRValueString(string), value] => + (string, FunctionRegistry_Core.FRType.matchReverse(value))->Ok + | _ => Error(impossibleError) + } + }) + ->E.A.R.firstErrorOrOpen + ->E.R2.fmap(Belt.Map.String.fromArray) + ->E.R2.fmap(Wrappers.evRecord) + inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.arrayOfArrays) + |> E.R2.bind(convertInternalItems) + }, + (), + ), ], (), ), @@ -481,30 +528,43 @@ to(5,10) ~name="List.make", ~definitions=[ //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. - FnDefinition.make(~name="listMake", ~inputs=[FRTypeNumber, FRTypeAny], ~run=(inputs, _) => { - switch inputs { - | [FRValueNumber(number), value] => - Belt.Array.make(E.Float.toInt(number), value) - ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) - ->Wrappers.evArray - ->Ok - | _ => Error(impossibleError) - } - }), + FnDefinition.make( + ~nameSpace=Some("List"), + ~requiresNamespace=true, + ~name="make", + ~inputs=[FRTypeNumber, FRTypeAny], + ~run=(inputs, _) => { + switch inputs { + | [FRValueNumber(number), value] => + Belt.Array.make(E.Float.toInt(number), value) + ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) + ->Wrappers.evArray + ->Ok + | _ => Error(impossibleError) + } + }, + (), + ), ], (), ), Function.make( ~name="upTo", ~definitions=[ - FnDefinition.make(~name="upTo", ~inputs=[FRTypeNumber, FRTypeNumber], ~run=(inputs, _) => - inputs - ->Prepare.ToValueTuple.twoNumbers - ->E.R2.fmap(((low, high)) => - E.A.Floats.range(low, high, (high -. low +. 1.0)->E.Float.toInt) - ->E.A2.fmap(Wrappers.evNumber) - ->Wrappers.evArray - ) + FnDefinition.make( + ~nameSpace=Some("List"), + ~requiresNamespace=true, + ~name="upTo", + ~inputs=[FRTypeNumber, FRTypeNumber], + ~run=(inputs, _) => + inputs + ->Prepare.ToValueTuple.twoNumbers + ->E.R2.fmap(((low, high)) => + E.A.Floats.range(low, high, (high -. low +. 1.0)->E.Float.toInt) + ->E.A2.fmap(Wrappers.evNumber) + ->Wrappers.evArray + ), + (), ), ], (), From c866cc812a5802ba1a8a90ae163356243940fe23 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 7 Jul 2022 18:09:41 -0700 Subject: [PATCH 02/40] wip --- .../FunctionRegistry_Core.res | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index be94ea99..202b11ff 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -329,6 +329,12 @@ module FnDefinition = { } } + let toFfiFn = (t: t): Reducer_Expression_T.optionFfiFn => + (args, environment) => run(t, args, environment)->E.R.toOption + + let toLambda = (t: t) => + Reducer_Module.convertOptionToFfiFn(t.name, toFfiFn(t))->Reducer_Module.eLambdaFFIValue + let make = (~nameSpace=None, ~requiresNamespace=true, ~name, ~inputs, ~run, ()): t => { name: name, nameSpace: nameSpace, @@ -368,6 +374,7 @@ module Function = { module Registry = { let toJson = (r: registry) => r->E.A2.fmap(Function.toJson) + let definitions = (r: registry) => r->E.A2.fmap(d => d.definitions)->E.A.concatMany /* There's a (potential+minor) bug here: If a function definition is called outside of the calls @@ -398,4 +405,27 @@ module Registry = { | _ => None } } + + let allNamespaces = (t: registry) => + t + ->E.A2.fmap(r => r.definitions) + ->Belt.Array.concatMany + ->E.A2.fmap(r => r.nameSpace) + ->E.A.O.concatSomes + ->E.A.uniq + + let makeModules = (t: registry) => { + let nameSpaces = allNamespaces(t) + nameSpaces->E.A2.fmap(nameSpace => { + let definitions = t->definitions->E.A2.filter(d => d.nameSpace === Some(nameSpace)) + + // E.A.reduce(definitions, Reducer_Module.emptyStdLib, (acc, d) => { + // let name = d.name + // let definition = FnDefinition.toLambda(d) + // let foo = Reducer_Module.defineFunction("Fhi", definition) + // }) + // let module = Module.make(nameSpace, functions) + // module + }) + } } From 7afae96cf487416b3b81eb784f3f3954876a858c Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 7 Jul 2022 18:30:56 -0700 Subject: [PATCH 03/40] Simple integration of module functionality --- .../FunctionRegistry_Core.res | 20 +++++++++---------- .../FunctionRegistry_Library.res | 2 +- .../SquiggleLibrary/SquiggleLibrary_Math.res | 4 +++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 202b11ff..923ea0b1 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -414,18 +414,18 @@ module Registry = { ->E.A.O.concatSomes ->E.A.uniq - let makeModules = (t: registry) => { + let makeModules = (prevBindings: Reducer_Module.t, t: registry): Reducer_Module.t => { let nameSpaces = allNamespaces(t) - nameSpaces->E.A2.fmap(nameSpace => { + let nameSpaceBindings = nameSpaces->E.A2.fmap(nameSpace => { let definitions = t->definitions->E.A2.filter(d => d.nameSpace === Some(nameSpace)) - - // E.A.reduce(definitions, Reducer_Module.emptyStdLib, (acc, d) => { - // let name = d.name - // let definition = FnDefinition.toLambda(d) - // let foo = Reducer_Module.defineFunction("Fhi", definition) - // }) - // let module = Module.make(nameSpace, functions) - // module + + let newModule = E.A.reduce(definitions, Reducer_Module.emptyStdLib, (acc, d) => { + acc->Reducer_Module.defineFunction(d.name, FnDefinition.toFfiFn(d)) + }) + (nameSpace, newModule) }) + E.A.reduce(nameSpaceBindings, prevBindings, (acc, (name, fn)) => + acc->Reducer_Module.defineModule(name, fn) + ) } } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 780356dc..e44bfb92 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -72,7 +72,7 @@ let registry = [ ~requiresNamespace=true, ~name="makeDiscrete", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), + ~run=(inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), (), ), ], diff --git a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res index d85927a1..436ed1fe 100644 --- a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res +++ b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res @@ -20,4 +20,6 @@ let mathBindings: Bindings.t = ->Bindings.fromArray let makeBindings = (previousBindings: Bindings.t): Bindings.t => - previousBindings->Bindings.defineModule("Math", mathBindings) + previousBindings + ->Bindings.defineModule("Math", mathBindings) + ->FunctionRegistry_Core.Registry.makeModules(FunctionRegistry_Library.registry) From cae59cb84b5f8f31ced946b0ff656ee08ec81e52 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 14 Jul 2022 13:31:48 -0700 Subject: [PATCH 04/40] Split up function definitions --- .../FunctionRegistry_Helpers.res | 90 -- .../FunctionRegistry_Library.res | 1232 ++++++++++------- 2 files changed, 726 insertions(+), 596 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res index dec88bca..115d5307 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -213,93 +213,3 @@ module Process = { twoValues(~fn=Helpers.wrapSymbolic(fn), ~values) } } - -module TwoArgDist = { - let process = (~fn, ~env, r) => - r - ->E.R.bind(Process.DistOrNumberToDist.twoValuesUsingSymbolicDist(~fn, ~values=_, ~env)) - ->E.R2.fmap(Wrappers.evDistribution) - - let make = (name, fn) => { - FnDefinition.make( - ~name, - ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], - ~run=(inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), - (), - ) - } - - let makeRecordP5P95 = (name, fn) => { - FnDefinition.make( - ~name, - ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], - ~run=(inputs, env) => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), - (), - ) - } - - let makeRecordMeanStdev = (name, fn) => { - FnDefinition.make( - ~name, - ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], - ~run=(inputs, env) => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), - (), - ) - } -} - -module OneArgDist = { - let process = (~fn, ~env, r) => - r - ->E.R.bind(Process.DistOrNumberToDist.oneValueUsingSymbolicDist(~fn, ~value=_, ~env)) - ->E.R2.fmap(Wrappers.evDistribution) - - let make = (name, fn) => - FnDefinition.make( - ~name, - ~inputs=[FRTypeDistOrNumber], - ~run=(inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), - (), - ) -} - -module ArrayNumberDist = { - let make = (name, fn) => { - FnDefinition.make( - ~name, - ~inputs=[FRTypeArray(FRTypeNumber)], - ~run=(inputs, _) => - Prepare.ToTypedArray.numbers(inputs) - ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) - ->E.R.bind(fn), - (), - ) - } - let make2 = (name, fn) => { - FnDefinition.make( - ~name, - ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _) => - Prepare.ToTypedArray.numbers(inputs) - ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) - ->E.R.bind(fn), - (), - ) - } -} - -module NumberToNumber = { - let make = (name, fn) => - FnDefinition.make( - ~name, - ~inputs=[FRTypeNumber], - ~run=(inputs, _) => { - inputs - ->getOrError(0) - ->E.R.bind(Prepare.oneNumber) - ->E.R2.fmap(fn) - ->E.R2.fmap(Wrappers.evNumber) - }, - (), - ) -} diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index c3c90c40..c21ae7cd 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -49,143 +49,225 @@ let inputsTodist = (inputs: array, makeDist) => { expressionValue } -let registryStart = [ - Function.make( - ~name="toContinuousPointSet", - ~definitions=[ +module PointSet = { + let nameSpace = Some("PointSet") + let requiresNamespace = true + let library = [ + Function.make( + ~name="PointSet.makeContinuous", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace, + ~name="makeContinuous", + ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], + ~run=(inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), + (), + ), + ], + (), + ), + Function.make( + ~name="PointSet.makeDiscrete", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace, + ~name="makeDiscrete", + ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], + ~run=(inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), + (), + ), + ], + (), + ), + ] +} + +module Functionn = { + let nameSpace = Some("Function") + let library = [ + Function.make( + ~name="Function.declare", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=true, + ~name="declare", + ~inputs=[Declaration.frType], + ~run=(inputs, _) => { + inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue) + }, + (), + ), + ], + (), + ), + ] +} + +module DistributionCreation = { + let nameSpace = Some("Dist") + module TwoArgDist = { + let process = (~fn, ~env, r) => + r + ->E.R.bind(Process.DistOrNumberToDist.twoValuesUsingSymbolicDist(~fn, ~values=_, ~env)) + ->E.R2.fmap(Wrappers.evDistribution) + + let make = (name, fn) => { FnDefinition.make( - ~nameSpace=Some("PointSet"), - ~requiresNamespace=true, - ~name="makeContinuous", - ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), + ~nameSpace, + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], + ~run=(inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), (), - ), - ], - (), - ), - Function.make( - ~name="toDiscretePointSet", - ~definitions=[ + ) + } + + let makeRecordP5P95 = (name, fn) => { FnDefinition.make( - ~nameSpace=Some("PointSet"), - ~requiresNamespace=true, - ~name="makeDiscrete", - ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), + ~nameSpace, + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], + ~run=(inputs, env) => + inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), (), - ), - ], - (), - ), - Function.make( - ~name="Declaration", - ~definitions=[ + ) + } + + let makeRecordMeanStdev = (name, fn) => { FnDefinition.make( - ~name="declareFn", - ~inputs=[Declaration.frType], - ~run=(inputs, _) => { - inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue) - }, + ~name, + ~nameSpace, + ~requiresNamespace=false, + ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], + ~run=(inputs, env) => + inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), (), - ), - ], - (), - ), - Function.make( - ~name="Normal", - ~examples=`normal(5,1) + ) + } + } + + module OneArgDist = { + let process = (~fn, ~env, r) => + r + ->E.R.bind(Process.DistOrNumberToDist.oneValueUsingSymbolicDist(~fn, ~value=_, ~env)) + ->E.R2.fmap(Wrappers.evDistribution) + + let make = (name, fn) => + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeDistOrNumber], + ~run=(inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), + (), + ) + } + let library = [ + Function.make( + ~name="Normal", + ~examples=`normal(5,1) normal({p5: 4, p95: 10}) normal({mean: 5, stdev: 2})`, - ~definitions=[ - TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), - TwoArgDist.makeRecordP5P95("normal", r => - twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok - ), - TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), - ], - (), - ), - Function.make( - ~name="Lognormal", - ~examples=`lognormal(0.5, 0.8) + ~definitions=[ + TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), + // TwoArgDist.makeRecordP5P95("normal", r => + // twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok + // ), + // TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), + ], + (), + ), + Function.make( + ~name="Lognormal", + ~examples=`lognormal(0.5, 0.8) lognormal({p5: 4, p95: 10}) lognormal({mean: 5, stdev: 2})`, - ~definitions=[ - TwoArgDist.make("lognormal", twoArgs(SymbolicDist.Lognormal.make)), - TwoArgDist.makeRecordP5P95("lognormal", r => - twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok - ), - TwoArgDist.makeRecordMeanStdev("lognormal", twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev)), - ], - (), - ), - Function.make( - ~name="Uniform", - ~examples=`uniform(10, 12)`, - ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], - (), - ), - Function.make( - ~name="Beta", - ~examples=`beta(20, 25) + ~definitions=[ + TwoArgDist.make("lognormal", twoArgs(SymbolicDist.Lognormal.make)), + TwoArgDist.makeRecordP5P95("lognormal", r => + twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok + ), + TwoArgDist.makeRecordMeanStdev( + "lognormal", + twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev), + ), + ], + (), + ), + Function.make( + ~name="Uniform", + ~examples=`uniform(10, 12)`, + ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], + (), + ), + Function.make( + ~name="Beta", + ~examples=`beta(20, 25) beta({mean: 0.39, stdev: 0.1})`, - ~definitions=[ - TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make)), - TwoArgDist.makeRecordMeanStdev("beta", twoArgs(SymbolicDist.Beta.fromMeanAndStdev)), - ], - (), - ), - Function.make( - ~name="Cauchy", - ~examples=`cauchy(5, 1)`, - ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], - (), - ), - Function.make( - ~name="Gamma", - ~examples=`gamma(5, 1)`, - ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], - (), - ), - Function.make( - ~name="Logistic", - ~examples=`gamma(5, 1)`, - ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], - (), - ), - Function.make( - ~name="To (Distribution)", - ~examples=`5 to 10 + ~definitions=[ + TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make)), + TwoArgDist.makeRecordMeanStdev("beta", twoArgs(SymbolicDist.Beta.fromMeanAndStdev)), + ], + (), + ), + Function.make( + ~name="Cauchy", + ~examples=`cauchy(5, 1)`, + ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], + (), + ), + Function.make( + ~name="Gamma", + ~examples=`gamma(5, 1)`, + ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], + (), + ), + Function.make( + ~name="Logistic", + ~examples=`gamma(5, 1)`, + ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], + (), + ), + Function.make( + ~name="To (Distribution)", + ~examples=`5 to 10 to(5,10) -5 to 5`, - ~definitions=[ - TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), - TwoArgDist.make( - "credibleIntervalToDistribution", - twoArgs(SymbolicDist.From90thPercentile.make), - ), - ], - (), - ), - Function.make( - ~name="Exponential", - ~examples=`exponential(2)`, - ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], - (), - ), - Function.make( - ~name="Bernoulli", - ~examples=`bernoulli(0.5)`, - ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], - (), - ), - Function.make( - ~name="PointMass", - ~examples=`pointMass(0.5)`, - ~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)], - (), - ), + ~definitions=[ + TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), + TwoArgDist.make( + "credibleIntervalToDistribution", + twoArgs(SymbolicDist.From90thPercentile.make), + ), + ], + (), + ), + Function.make( + ~name="Exponential", + ~examples=`exponential(2)`, + ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], + (), + ), + Function.make( + ~name="Bernoulli", + ~examples=`bernoulli(0.5)`, + ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], + (), + ), + Function.make( + ~name="PointMass", + ~examples=`pointMass(0.5)`, + ~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)], + (), + ), + ] +} + +let registryStart = [ Function.make( ~name="toContinuousPointSet", ~description="Converts a set of points to a continuous distribution", @@ -247,390 +329,528 @@ to(5,10) ~isExperimental=true, (), ), - Function.make( - ~name="Floor", - ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], - (), - ), - Function.make( - ~name="Ceiling", - ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], - (), - ), - Function.make( - ~name="Absolute Value", - ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], - (), - ), - Function.make(~name="Exponent", ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], ()), - Function.make(~name="Log", ~definitions=[NumberToNumber.make("log", Js.Math.log)], ()), - Function.make( - ~name="Log Base 10", - ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], - (), - ), - Function.make(~name="Log Base 2", ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], ()), - Function.make(~name="Round", ~definitions=[NumberToNumber.make("round", Js.Math.round)], ()), - Function.make( - ~name="Sum", - ~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="Product", - ~definitions=[ - ArrayNumberDist.make("product", r => r->E.A.Floats.product->Wrappers.evNumber->Ok), - ], - (), - ), - Function.make( - ~name="Min", - ~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="Max", - ~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="Mean", - ~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="Geometric Mean", - ~definitions=[ - ArrayNumberDist.make("geomean", r => r->E.A.Floats.geomean->Wrappers.evNumber->Ok), - ], - (), - ), - Function.make( - ~name="Standard Deviation", - ~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="Variance", - ~definitions=[ - ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok), - ], - (), - ), - Function.make( - ~name="First", - ~definitions=[ - ArrayNumberDist.make2("first", r => - r->E.A.first |> E.O.toResult(impossibleError) |> E.R.fmap(Wrappers.evNumber) - ), - ], - (), - ), - Function.make( - ~name="Last", - ~definitions=[ - ArrayNumberDist.make2("last", r => - r->E.A.last |> E.O.toResult(impossibleError) |> E.R.fmap(Wrappers.evNumber) - ), - ], - (), - ), - Function.make( - ~name="Sort", - ~definitions=[ - ArrayNumberDist.make("sort", r => - r->E.A.Floats.sort->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="Reverse", - ~definitions=[ - ArrayNumberDist.make("reverse", r => - r->Belt_Array.reverse->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="Cumulative Sum", - ~definitions=[ - ArrayNumberDist.make("cumsum", r => - r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="Cumulative Prod", - ~definitions=[ - ArrayNumberDist.make("cumprod", r => - r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="Diff", - ~definitions=[ - ArrayNumberDist.make("diff", r => - r->E.A.Floats.diff->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="Dict.merge", - ~definitions=[ - FnDefinition.make( - ~nameSpace=Some("Dict"), - ~requiresNamespace=true, - ~name="merge", - ~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)], - ~run=(inputs, _) => { - switch inputs { - | [FRValueDict(d1), FRValueDict(d2)] => { - let newDict = - E.Dict.concat(d1, d2) |> Js.Dict.map((. r) => - FunctionRegistry_Core.FRType.matchReverse(r) - ) - newDict->Js.Dict.entries->Belt.Map.String.fromArray->Wrappers.evRecord->Ok - } - | _ => Error(impossibleError) - } - }, - (), - ), - ], - (), - ), - //TODO: Make sure that two functions can't have the same name. This causes chaos elsewhere. - Function.make( - ~name="Dict.mergeMany", - ~definitions=[ - FnDefinition.make( - ~nameSpace=Some("Dict"), - ~requiresNamespace=true, - ~name="mergeMany", - ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], - ~run=(inputs, _) => - inputs - ->Prepare.ToTypedArray.dicts - ->E.R2.fmap(E.Dict.concatMany) - ->E.R2.fmap(Js.Dict.map((. r) => FunctionRegistry_Core.FRType.matchReverse(r))) - ->E.R2.fmap(r => r->Js.Dict.entries->Belt.Map.String.fromArray) - ->E.R2.fmap(Wrappers.evRecord), - (), - ), - ], - (), - ), - Function.make( - ~name="Dict.keys", - ~definitions=[ - FnDefinition.make( - ~nameSpace=Some("Dict"), - ~requiresNamespace=true, - ~name="keys", - ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _) => - switch inputs { - | [FRValueDict(d1)] => - Js.Dict.keys(d1)->E.A2.fmap(Wrappers.evString)->Wrappers.evArray->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="Dict.values", - ~definitions=[ - FnDefinition.make( - ~nameSpace=Some("Dict"), - ~requiresNamespace=true, - ~name="values", - ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _) => - switch inputs { - | [FRValueDict(d1)] => - Js.Dict.values(d1) - ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) - ->Wrappers.evArray - ->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="Dict.toList", - ~definitions=[ - FnDefinition.make( - ~nameSpace=Some("Dict"), - ~requiresNamespace=true, - ~name="toList", - ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _) => - switch inputs { - | [FRValueDict(dict)] => - dict - ->Js.Dict.entries - ->E.A2.fmap(((key, value)) => - Wrappers.evArray([ - Wrappers.evString(key), - FunctionRegistry_Core.FRType.matchReverse(value), - ]) - ) - ->Wrappers.evArray - ->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="Dict.fromList", - ~definitions=[ - FnDefinition.make( - ~nameSpace=Some("Dict"), - ~requiresNamespace=true, - ~name="fromList", - ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], - ~run=(inputs, _) => { - let convertInternalItems = items => - items - ->E.A2.fmap(item => { - switch item { - | [FRValueString(string), value] => - (string, FunctionRegistry_Core.FRType.matchReverse(value))->Ok - | _ => Error(impossibleError) - } - }) - ->E.A.R.firstErrorOrOpen - ->E.R2.fmap(Belt.Map.String.fromArray) - ->E.R2.fmap(Wrappers.evRecord) - inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.arrayOfArrays) - |> E.R2.bind(convertInternalItems) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="List.make", - ~definitions=[ - //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. - FnDefinition.make( - ~nameSpace=Some("List"), - ~requiresNamespace=true, - ~name="make", - ~inputs=[FRTypeNumber, FRTypeAny], - ~run=(inputs, _) => { - switch inputs { - | [FRValueNumber(number), value] => - Belt.Array.make(E.Float.toInt(number), value) - ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) - ->Wrappers.evArray - ->Ok - | _ => Error(impossibleError) - } - }, - (), - ), - ], - (), - ), - Function.make( - ~name="upTo", - ~definitions=[ - FnDefinition.make( - ~nameSpace=Some("List"), - ~requiresNamespace=true, - ~name="upTo", - ~inputs=[FRTypeNumber, FRTypeNumber], - ~run=(inputs, _) => - inputs - ->Prepare.ToValueTuple.twoNumbers - ->E.R2.fmap(((low, high)) => - E.A.Floats.range(low, high, (high -. low +. 1.0)->E.Float.toInt) - ->E.A2.fmap(Wrappers.evNumber) - ->Wrappers.evArray - ), - (), - ), - ], - (), - ), ] -let runScoring = (estimate, answer, prior, env) => { - GenericDist.Score.logScore(~estimate, ~answer, ~prior, ~env) - ->E.R2.fmap(FunctionRegistry_Helpers.Wrappers.evNumber) - ->E.R2.errMap(DistributionTypes.Error.toString) +module Number = { + let nameSpace = Some("Number") + let requiresNamespace = false + + module NumberToNumber = { + let make = (name, fn) => + FnDefinition.make( + ~nameSpace, + ~requiresNamespace, + ~name, + ~inputs=[FRTypeNumber], + ~run=(inputs, _) => { + inputs + ->getOrError(0) + ->E.R.bind(Prepare.oneNumber) + ->E.R2.fmap(fn) + ->E.R2.fmap(Wrappers.evNumber) + }, + (), + ) + } + + module ArrayNumberDist = { + let make = (name, fn) => { + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeArray(FRTypeNumber)], + ~run=(inputs, _) => + Prepare.ToTypedArray.numbers(inputs) + ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) + ->E.R.bind(fn), + (), + ) + } + let make2 = (name, fn) => { + FnDefinition.make( + ~name, + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _) => + Prepare.ToTypedArray.numbers(inputs) + ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) + ->E.R.bind(fn), + (), + ) + } + } + + let library = [ + Function.make( + ~name="Floor", + ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], + (), + ), + Function.make( + ~name="Ceiling", + ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], + (), + ), + Function.make( + ~name="Absolute Value", + ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], + (), + ), + Function.make(~name="Exponent", ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], ()), + Function.make(~name="Log", ~definitions=[NumberToNumber.make("log", Js.Math.log)], ()), + Function.make( + ~name="Log Base 10", + ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], + (), + ), + Function.make(~name="Log Base 2", ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], ()), + Function.make(~name="Round", ~definitions=[NumberToNumber.make("round", Js.Math.round)], ()), + Function.make( + ~name="Sum", + ~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="Product", + ~definitions=[ + ArrayNumberDist.make("product", r => r->E.A.Floats.product->Wrappers.evNumber->Ok), + ], + (), + ), + Function.make( + ~name="Min", + ~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="Max", + ~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="Mean", + ~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="Geometric Mean", + ~definitions=[ + ArrayNumberDist.make("geomean", r => r->E.A.Floats.geomean->Wrappers.evNumber->Ok), + ], + (), + ), + Function.make( + ~name="Standard Deviation", + ~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="Variance", + ~definitions=[ + ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok), + ], + (), + ), + Function.make( + ~name="Sort", + ~definitions=[ + ArrayNumberDist.make("sort", r => + r->E.A.Floats.sort->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), + Function.make( + ~name="Cumulative Sum", + ~definitions=[ + ArrayNumberDist.make("cumsum", r => + r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), + Function.make( + ~name="Cumulative Prod", + ~definitions=[ + ArrayNumberDist.make("cumprod", r => + r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), + Function.make( + ~name="Diff", + ~definitions=[ + ArrayNumberDist.make("diff", r => + r->E.A.Floats.diff->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), + ] } -let scoreFunctions = [ - Function.make( - ~name="Score", - ~definitions=[ - FnDefinition.make( - ~name="logScore", - ~inputs=[ - FRTypeRecord([ - ("estimate", FRTypeDist), - ("answer", FRTypeDistOrNumber), - ("prior", FRTypeDist), - ]), - ], - ~run=(inputs, env) => { - switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) { - | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d)), FRValueDist(prior)]) => - runScoring(estimate, Score_Dist(d), Some(prior), env) - | Ok([ - FRValueDist(estimate), - FRValueDistOrNumber(FRValueNumber(d)), - FRValueDist(prior), - ]) => - runScoring(estimate, Score_Scalar(d), Some(prior), env) - | Error(e) => Error(e) - | _ => Error(FunctionRegistry_Helpers.impossibleError) - } - }, - ), - FnDefinition.make( - ~name="logScore", - ~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])], - ~run=(inputs, env) => { - switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) { - | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) => - runScoring(estimate, Score_Dist(d), None, env) - | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueNumber(d))]) => - runScoring(estimate, Score_Scalar(d), None, env) - | Error(e) => Error(e) - | _ => Error(FunctionRegistry_Helpers.impossibleError) - } - }, - ), - FnDefinition.make(~name="klDivergence", ~inputs=[FRTypeDist, FRTypeDist], ~run=( - inputs, - env, - ) => { - switch inputs { - | [FRValueDist(estimate), FRValueDist(d)] => runScoring(estimate, Score_Dist(d), None, env) - | _ => Error(FunctionRegistry_Helpers.impossibleError) - } - }), - ], - (), - ), -] +module Dict = { + let nameSpace = Some("Dict") + let library = [ + Function.make( + ~name="merge", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=true, + ~name="merge", + ~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)], + ~run=(inputs, _) => { + switch inputs { + | [FRValueDict(d1), FRValueDict(d2)] => { + let newDict = + E.Dict.concat(d1, d2) |> Js.Dict.map((. r) => + FunctionRegistry_Core.FRType.matchReverse(r) + ) + newDict->Js.Dict.entries->Belt.Map.String.fromArray->Wrappers.evRecord->Ok + } + | _ => Error(impossibleError) + } + }, + (), + ), + ], + (), + ), + //TODO: Make sure that two functions can't have the same name. This causes chaos elsewhere. + Function.make( + ~name="mergeMany", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=true, + ~name="mergeMany", + ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], + ~run=(inputs, _) => + inputs + ->Prepare.ToTypedArray.dicts + ->E.R2.fmap(E.Dict.concatMany) + ->E.R2.fmap(Js.Dict.map((. r) => FunctionRegistry_Core.FRType.matchReverse(r))) + ->E.R2.fmap(r => r->Js.Dict.entries->Belt.Map.String.fromArray) + ->E.R2.fmap(Wrappers.evRecord), + (), + ), + ], + (), + ), + Function.make( + ~name="keys", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=true, + ~name="keys", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _) => + switch inputs { + | [FRValueDict(d1)] => + Js.Dict.keys(d1)->E.A2.fmap(Wrappers.evString)->Wrappers.evArray->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="values", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=true, + ~name="values", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _) => + switch inputs { + | [FRValueDict(d1)] => + Js.Dict.values(d1) + ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) + ->Wrappers.evArray + ->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="toList", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=true, + ~name="toList", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _) => + switch inputs { + | [FRValueDict(dict)] => + dict + ->Js.Dict.entries + ->E.A2.fmap(((key, value)) => + Wrappers.evArray([ + Wrappers.evString(key), + FunctionRegistry_Core.FRType.matchReverse(value), + ]) + ) + ->Wrappers.evArray + ->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="fromList", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=true, + ~name="fromList", + ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], + ~run=(inputs, _) => { + let convertInternalItems = items => + items + ->E.A2.fmap(item => { + switch item { + | [FRValueString(string), value] => + (string, FunctionRegistry_Core.FRType.matchReverse(value))->Ok + | _ => Error(impossibleError) + } + }) + ->E.A.R.firstErrorOrOpen + ->E.R2.fmap(Belt.Map.String.fromArray) + ->E.R2.fmap(Wrappers.evRecord) + inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.arrayOfArrays) + |> E.R2.bind(convertInternalItems) + }, + (), + ), + ], + (), + ), + ] +} -let registry = E.A.append(registryStart, scoreFunctions) +module List = { + let nameSpace = Some("List") + let requiresNamespace = true + + let library = [ + Function.make( + ~name="List.make", + ~definitions=[ + //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. + FnDefinition.make( + ~nameSpace, + ~requiresNamespace, + ~name="make", + ~inputs=[FRTypeNumber, FRTypeAny], + ~run=(inputs, _) => { + switch inputs { + | [FRValueNumber(number), value] => + Belt.Array.make(E.Float.toInt(number), value) + ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) + ->Wrappers.evArray + ->Ok + | _ => Error(impossibleError) + } + }, + (), + ), + ], + (), + ), + Function.make( + ~name="List.upTo", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace, + ~name="upTo", + ~inputs=[FRTypeNumber, FRTypeNumber], + ~run=(inputs, _) => + inputs + ->Prepare.ToValueTuple.twoNumbers + ->E.R2.fmap(((low, high)) => + E.A.Floats.range(low, high, (high -. low +. 1.0)->E.Float.toInt) + ->E.A2.fmap(Wrappers.evNumber) + ->Wrappers.evArray + ), + (), + ), + ], + (), + ), + Function.make( + ~name="List.first", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace, + ~name="first", + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _) => + switch inputs { + | [FRValueArray(array)] => + E.A.first(array) + |> E.O.toResult("No first element") + |> E.R.fmap(FunctionRegistry_Core.FRType.matchReverse) + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="List.last", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=false, + ~name="last", + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _) => + switch inputs { + | [FRValueArray(array)] => + E.A.last(array) + |> E.O.toResult("No first element") + |> E.R.fmap(FunctionRegistry_Core.FRType.matchReverse) + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="List.reverse", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace=false, + ~name="last", + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _) => + switch inputs { + | [FRValueArray(array)] => + Belt.Array.reverse(array) + ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) + ->Wrappers.evArray + ->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + ] +} + +module Scoring = { + let nameSpace = Some("Dist") + let requiresNamespace = false + + let runScoring = (estimate, answer, prior, env) => { + GenericDist.Score.logScore(~estimate, ~answer, ~prior, ~env) + ->E.R2.fmap(FunctionRegistry_Helpers.Wrappers.evNumber) + ->E.R2.errMap(DistributionTypes.Error.toString) + } + + let library = [ + Function.make( + ~name="logScore", + ~definitions=[ + FnDefinition.make( + ~nameSpace, + ~requiresNamespace, + ~name="logScore", + ~inputs=[ + FRTypeRecord([ + ("estimate", FRTypeDist), + ("answer", FRTypeDistOrNumber), + ("prior", FRTypeDist), + ]), + ], + ~run=(inputs, env) => { + switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) { + | Ok([ + FRValueDist(estimate), + FRValueDistOrNumber(FRValueDist(d)), + FRValueDist(prior), + ]) => + runScoring(estimate, Score_Dist(d), Some(prior), env) + | Ok([ + FRValueDist(estimate), + FRValueDistOrNumber(FRValueNumber(d)), + FRValueDist(prior), + ]) => + runScoring(estimate, Score_Scalar(d), Some(prior), env) + | Error(e) => Error(e) + | _ => Error(FunctionRegistry_Helpers.impossibleError) + } + }, + (), + ), + FnDefinition.make( + ~name="logScore", + ~nameSpace, + ~requiresNamespace, + ~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])], + ~run=(inputs, env) => { + switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) { + | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) => + runScoring(estimate, Score_Dist(d), None, env) + | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueNumber(d))]) => + runScoring(estimate, Score_Scalar(d), None, env) + | Error(e) => Error(e) + | _ => Error(FunctionRegistry_Helpers.impossibleError) + } + }, + (), + ), + ], + (), + ), + Function.make( + ~name="klDivergence", + ~definitions=[ + FnDefinition.make( + ~name="klDivergence", + ~nameSpace, + ~requiresNamespace, + ~inputs=[FRTypeDist, FRTypeDist], + ~run=(inputs, env) => { + switch inputs { + | [FRValueDist(estimate), FRValueDist(d)] => + runScoring(estimate, Score_Dist(d), None, env) + | _ => Error(FunctionRegistry_Helpers.impossibleError) + } + }, + (), + ), + ], + (), + ), + ] +} + +let registry = Belt.Array.concatMany([ + PointSet.library, + Functionn.library, + Number.library, + Dict.library, + List.library, + DistributionCreation.library, + Scoring.library, +]) From feb198d20553e316cb0f281191f0bafedabdaa54 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 14 Jul 2022 14:53:53 -0700 Subject: [PATCH 05/40] Add and use extra pathway for FunctionRegistry to use internalValues directly --- .../FunctionRegistry_Core.res | 4 +- .../FunctionRegistry_Library.res | 164 ++++++++++-------- 2 files changed, 89 insertions(+), 79 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 8a3c28ec..51247fde 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -44,7 +44,7 @@ type fnDefinition = { requiresNamespace: bool, name: string, inputs: array, - run: (array, GenericDist.env) => result, + run: (array, array, GenericDist.env)=> result } type function = { @@ -327,7 +327,7 @@ module FnDefinition = { let run = (t: t, args: array, env: GenericDist.env) => { let argValues = FRType.matchWithExpressionValueArray(t.inputs, args) switch argValues { - | Some(values) => t.run(values, env) + | Some(values) => t.run(args, values, env) | None => Error("Incorrect Types") } } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index c21ae7cd..efb8d584 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -61,7 +61,7 @@ module PointSet = { ~requiresNamespace, ~name="makeContinuous", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), + ~run=(_, inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), (), ), ], @@ -75,7 +75,7 @@ module PointSet = { ~requiresNamespace, ~name="makeDiscrete", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), + ~run=(_, inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), (), ), ], @@ -95,7 +95,7 @@ module Functionn = { ~requiresNamespace=true, ~name="declare", ~inputs=[Declaration.frType], - ~run=(inputs, _) => { + ~run=(_, inputs, _) => { inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue) }, (), @@ -120,7 +120,7 @@ module DistributionCreation = { ~requiresNamespace=false, ~name, ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], - ~run=(inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), + ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), (), ) } @@ -131,7 +131,7 @@ module DistributionCreation = { ~requiresNamespace=false, ~name, ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], - ~run=(inputs, env) => + ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), (), ) @@ -143,7 +143,7 @@ module DistributionCreation = { ~nameSpace, ~requiresNamespace=false, ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], - ~run=(inputs, env) => + ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), (), ) @@ -162,7 +162,7 @@ module DistributionCreation = { ~requiresNamespace=false, ~name, ~inputs=[FRTypeDistOrNumber], - ~run=(inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), + ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), (), ) } @@ -281,7 +281,7 @@ let registryStart = [ FnDefinition.make( ~name="toContinuousPointSet", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), + ~run=(_, inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), (), ), ], @@ -300,7 +300,7 @@ let registryStart = [ FnDefinition.make( ~name="toDiscretePointSet", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), + ~run=(_, inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), (), ), ], @@ -320,7 +320,7 @@ let registryStart = [ FnDefinition.make( ~name="declareFn", ~inputs=[Declaration.frType], - ~run=(inputs, _) => { + ~run=(_, inputs, _) => { inputs->E.A.unsafe_get(0)->Declaration.fromExpressionValue }, (), @@ -342,7 +342,7 @@ module Number = { ~requiresNamespace, ~name, ~inputs=[FRTypeNumber], - ~run=(inputs, _) => { + ~run=(_, inputs, _) => { inputs ->getOrError(0) ->E.R.bind(Prepare.oneNumber) @@ -360,7 +360,7 @@ module Number = { ~requiresNamespace=false, ~name, ~inputs=[FRTypeArray(FRTypeNumber)], - ~run=(inputs, _) => + ~run=(_, inputs, _) => Prepare.ToTypedArray.numbers(inputs) ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) ->E.R.bind(fn), @@ -371,7 +371,7 @@ module Number = { FnDefinition.make( ~name, ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _) => + ~run=(_, inputs, _) => Prepare.ToTypedArray.numbers(inputs) ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) ->E.R.bind(fn), @@ -492,6 +492,32 @@ module Number = { module Dict = { let nameSpace = Some("Dict") + module Internals = { + type t = ReducerInterface_InternalExpressionValue.map + + let keys = (a: t): internalExpressionValue => IEvArray( + Belt.Map.String.keysToArray(a)->E.A2.fmap(Wrappers.evString), + ) + + let values = (a: t): internalExpressionValue => IEvArray(Belt.Map.String.valuesToArray(a)) + + let toList = (a: t): internalExpressionValue => + Belt.Map.String.toArray(a) + ->E.A2.fmap(((key, value)) => Wrappers.evArray([IEvString(key), value])) + ->Wrappers.evArray + + let merge = (a: t, b: t): internalExpressionValue => IEvRecord( + Belt.Map.String.merge(a, b, (_, _, c) => c), + ) + + //Belt.Map.String has a function for mergeMany, but I couldn't understand how to use it yet. + let mergeMany = (a: array): internalExpressionValue => { + let mergedValues = + a->E.A2.fmap(Belt.Map.String.toArray)->Belt.Array.concatMany->Belt.Map.String.fromArray + IEvRecord(mergedValues) + } + } + let library = [ Function.make( ~name="merge", @@ -501,15 +527,9 @@ module Dict = { ~requiresNamespace=true, ~name="merge", ~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)], - ~run=(inputs, _) => { + ~run=(inputs, _, _) => { switch inputs { - | [FRValueDict(d1), FRValueDict(d2)] => { - let newDict = - E.Dict.concat(d1, d2) |> Js.Dict.map((. r) => - FunctionRegistry_Core.FRType.matchReverse(r) - ) - newDict->Js.Dict.entries->Belt.Map.String.fromArray->Wrappers.evRecord->Ok - } + | [IEvRecord(d1), IEvRecord(d2)] => Internals.merge(d1, d2)->Ok | _ => Error(impossibleError) } }, @@ -518,7 +538,7 @@ module Dict = { ], (), ), - //TODO: Make sure that two functions can't have the same name. This causes chaos elsewhere. + //TODO: Change to use new mergeMany() function. Function.make( ~name="mergeMany", ~definitions=[ @@ -527,7 +547,7 @@ module Dict = { ~requiresNamespace=true, ~name="mergeMany", ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], - ~run=(inputs, _) => + ~run=(_, inputs, _) => inputs ->Prepare.ToTypedArray.dicts ->E.R2.fmap(E.Dict.concatMany) @@ -547,10 +567,9 @@ module Dict = { ~requiresNamespace=true, ~name="keys", ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _) => + ~run=(inputs, _, _) => switch inputs { - | [FRValueDict(d1)] => - Js.Dict.keys(d1)->E.A2.fmap(Wrappers.evString)->Wrappers.evArray->Ok + | [IEvRecord(d1)] => Internals.keys(d1)->Ok | _ => Error(impossibleError) }, (), @@ -566,13 +585,9 @@ module Dict = { ~requiresNamespace=true, ~name="values", ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _) => + ~run=(inputs, _, _) => switch inputs { - | [FRValueDict(d1)] => - Js.Dict.values(d1) - ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) - ->Wrappers.evArray - ->Ok + | [IEvRecord(d1)] => Internals.values(d1)->Ok | _ => Error(impossibleError) }, (), @@ -588,19 +603,9 @@ module Dict = { ~requiresNamespace=true, ~name="toList", ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _) => + ~run=(inputs, _, _) => switch inputs { - | [FRValueDict(dict)] => - dict - ->Js.Dict.entries - ->E.A2.fmap(((key, value)) => - Wrappers.evArray([ - Wrappers.evString(key), - FunctionRegistry_Core.FRType.matchReverse(value), - ]) - ) - ->Wrappers.evArray - ->Ok + | [IEvRecord(dict)] => dict->Internals.toList->Ok | _ => Error(impossibleError) }, (), @@ -616,7 +621,7 @@ module Dict = { ~requiresNamespace=true, ~name="fromList", ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], - ~run=(inputs, _) => { + ~run=(_, inputs, _) => { let convertInternalItems = items => items ->E.A2.fmap(item => { @@ -644,6 +649,29 @@ module List = { let nameSpace = Some("List") let requiresNamespace = true + module Internals = { + let makeFromNumber = ( + n: float, + value: internalExpressionValue, + ): internalExpressionValue => IEvArray(Belt.Array.make(E.Float.toInt(n), value)) + + let upTo = (low: float, high: float): internalExpressionValue => IEvArray( + E.A.Floats.range(low, high, (high -. low +. 1.0)->E.Float.toInt)->E.A2.fmap( + Wrappers.evNumber, + ), + ) + + let first = (v: array): result => + v->E.A.first |> E.O.toResult("No first element") + + let last = (v: array): result => + v->E.A.last |> E.O.toResult("No last element") + + let reverse = (array: array): internalExpressionValue => IEvArray( + Belt.Array.reverse(array), + ) + } + let library = [ Function.make( ~name="List.make", @@ -654,13 +682,9 @@ module List = { ~requiresNamespace, ~name="make", ~inputs=[FRTypeNumber, FRTypeAny], - ~run=(inputs, _) => { + ~run=(inputs, _, _) => { switch inputs { - | [FRValueNumber(number), value] => - Belt.Array.make(E.Float.toInt(number), value) - ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) - ->Wrappers.evArray - ->Ok + | [IEvNumber(number), value] => Internals.makeFromNumber(number, value)->Ok | _ => Error(impossibleError) } }, @@ -677,14 +701,10 @@ module List = { ~requiresNamespace, ~name="upTo", ~inputs=[FRTypeNumber, FRTypeNumber], - ~run=(inputs, _) => + ~run=(_, inputs, _) => inputs ->Prepare.ToValueTuple.twoNumbers - ->E.R2.fmap(((low, high)) => - E.A.Floats.range(low, high, (high -. low +. 1.0)->E.Float.toInt) - ->E.A2.fmap(Wrappers.evNumber) - ->Wrappers.evArray - ), + ->E.R2.fmap(((low, high)) => Internals.upTo(low, high)), (), ), ], @@ -698,12 +718,9 @@ module List = { ~requiresNamespace, ~name="first", ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _) => + ~run=(inputs, _, _) => switch inputs { - | [FRValueArray(array)] => - E.A.first(array) - |> E.O.toResult("No first element") - |> E.R.fmap(FunctionRegistry_Core.FRType.matchReverse) + | [IEvArray(array)] => Internals.first(array) | _ => Error(impossibleError) }, (), @@ -719,12 +736,9 @@ module List = { ~requiresNamespace=false, ~name="last", ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _) => + ~run=(inputs, _, _) => switch inputs { - | [FRValueArray(array)] => - E.A.last(array) - |> E.O.toResult("No first element") - |> E.R.fmap(FunctionRegistry_Core.FRType.matchReverse) + | [IEvArray(array)] => Internals.last(array) | _ => Error(impossibleError) }, (), @@ -738,15 +752,11 @@ module List = { FnDefinition.make( ~nameSpace, ~requiresNamespace=false, - ~name="last", + ~name="reverse", ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _) => + ~run=(inputs, _, _) => switch inputs { - | [FRValueArray(array)] => - Belt.Array.reverse(array) - ->E.A2.fmap(FunctionRegistry_Core.FRType.matchReverse) - ->Wrappers.evArray - ->Ok + | [IEvArray(array)] => Internals.reverse(array)->Ok | _ => Error(impossibleError) }, (), @@ -782,7 +792,7 @@ module Scoring = { ("prior", FRTypeDist), ]), ], - ~run=(inputs, env) => { + ~run=(_, inputs, env) => { switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) { | Ok([ FRValueDist(estimate), @@ -807,7 +817,7 @@ module Scoring = { ~nameSpace, ~requiresNamespace, ~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])], - ~run=(inputs, env) => { + ~run=(_, inputs, env) => { switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) { | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) => runScoring(estimate, Score_Dist(d), None, env) @@ -830,7 +840,7 @@ module Scoring = { ~nameSpace, ~requiresNamespace, ~inputs=[FRTypeDist, FRTypeDist], - ~run=(inputs, env) => { + ~run=(_, inputs, env) => { switch inputs { | [FRValueDist(estimate), FRValueDist(d)] => runScoring(estimate, Score_Dist(d), None, env) From fc95253dd5046d2938208ed1370771c93407a202 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 14 Jul 2022 15:15:03 -0700 Subject: [PATCH 06/40] Cleanup of Dict Fromlist in Function Registry Library --- .../FunctionRegistry_Library.res | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index efb8d584..6fa23892 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -506,6 +506,21 @@ module Dict = { ->E.A2.fmap(((key, value)) => Wrappers.evArray([IEvString(key), value])) ->Wrappers.evArray + let fromList = (items: array): result< + internalExpressionValue, + string, + > => + items + ->E.A2.fmap(item => { + switch (item: internalExpressionValue) { + | IEvArray([IEvString(string), value]) => (string, value)->Ok + | _ => Error(impossibleError) + } + }) + ->E.A.R.firstErrorOrOpen + ->E.R2.fmap(Belt.Map.String.fromArray) + ->E.R2.fmap(Wrappers.evRecord) + let merge = (a: t, b: t): internalExpressionValue => IEvRecord( Belt.Map.String.merge(a, b, (_, _, c) => c), ) @@ -621,22 +636,11 @@ module Dict = { ~requiresNamespace=true, ~name="fromList", ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], - ~run=(_, inputs, _) => { - let convertInternalItems = items => - items - ->E.A2.fmap(item => { - switch item { - | [FRValueString(string), value] => - (string, FunctionRegistry_Core.FRType.matchReverse(value))->Ok - | _ => Error(impossibleError) - } - }) - ->E.A.R.firstErrorOrOpen - ->E.R2.fmap(Belt.Map.String.fromArray) - ->E.R2.fmap(Wrappers.evRecord) - inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.arrayOfArrays) - |> E.R2.bind(convertInternalItems) - }, + ~run=(inputs, _, _) => + switch inputs { + | [IEvArray(items)] => Internals.fromList(items) + | _ => Error(impossibleError) + }, (), ), ], From c3b0009fb88526cb48e6d141c5bc98dd2337b06c Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 14 Jul 2022 16:13:22 -0700 Subject: [PATCH 07/40] Minor cleanup --- .../FunctionRegistry_Library.res | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 6fa23892..2c0238ce 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -89,6 +89,15 @@ module Functionn = { let library = [ Function.make( ~name="Function.declare", + ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", + ~examples=`declareFn({ + fn: {|a,b| a }, + inputs: [ + {min: 0, max: 100}, + {min: 30, max: 50} + ] +})`, + ~isExperimental=true, ~definitions=[ FnDefinition.make( ~nameSpace, @@ -174,10 +183,10 @@ normal({p5: 4, p95: 10}) normal({mean: 5, stdev: 2})`, ~definitions=[ TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), - // TwoArgDist.makeRecordP5P95("normal", r => - // twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok - // ), - // TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), + TwoArgDist.makeRecordP5P95("normal", r => + twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok + ), + TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), ], (), ), @@ -306,29 +315,6 @@ let registryStart = [ ], (), ), - Function.make( - ~name="Declaration (Continuous Function)", - ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", - ~examples=`declareFn({ - fn: {|a,b| a }, - inputs: [ - {min: 0, max: 100}, - {min: 30, max: 50} - ] -})`, - ~definitions=[ - FnDefinition.make( - ~name="declareFn", - ~inputs=[Declaration.frType], - ~run=(_, inputs, _) => { - inputs->E.A.unsafe_get(0)->Declaration.fromExpressionValue - }, - (), - ), - ], - ~isExperimental=true, - (), - ), ] module Number = { From 3c396e0cccb6a3bf70ebb757a09edaba238c5184 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 14 Jul 2022 16:43:38 -0700 Subject: [PATCH 08/40] FunctionRegistry examples should be an array --- .../FunctionRegistry_Core.res | 6 +- .../FunctionRegistry_Library.res | 118 ++++++------------ 2 files changed, 42 insertions(+), 82 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 51247fde..c50a8297 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -50,7 +50,7 @@ type fnDefinition = { type function = { name: string, definitions: array, - examples: option, + examples: array, description: option, isExperimental: bool, } @@ -353,7 +353,7 @@ module Function = { type functionJson = { name: string, definitions: array, - examples: option, + examples: array, description: option, isExperimental: bool, } @@ -361,7 +361,7 @@ module Function = { let make = (~name, ~definitions, ~examples=?, ~description=?, ~isExperimental=false, ()): t => { name: name, definitions: definitions, - examples: examples, + examples: examples |> E.O.default([]), isExperimental: isExperimental, description: description, } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 2c0238ce..465a5834 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -30,28 +30,29 @@ module Declaration = { } } -let inputsTodist = (inputs: array, makeDist) => { - let array = inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.openA) - let xyCoords = - array->E.R.bind(xyCoords => - xyCoords - ->E.A2.fmap(xyCoord => - [xyCoord]->Prepare.ToValueArray.Record.twoArgs->E.R.bind(Prepare.ToValueTuple.twoNumbers) - ) - ->E.A.R.firstErrorOrOpen - ) - let expressionValue = - xyCoords - ->E.R.bind(r => r->XYShape.T.makeFromZipped->E.R2.errMap(XYShape.Error.toString)) - ->E.R2.fmap(r => ReducerInterface_InternalExpressionValue.IEvDistribution( - PointSet(makeDist(r)), - )) - expressionValue -} - module PointSet = { let nameSpace = Some("PointSet") let requiresNamespace = true + + let inputsTodist = (inputs: array, makeDist) => { + let array = inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.openA) + let xyCoords = + array->E.R.bind(xyCoords => + xyCoords + ->E.A2.fmap(xyCoord => + [xyCoord]->Prepare.ToValueArray.Record.twoArgs->E.R.bind(Prepare.ToValueTuple.twoNumbers) + ) + ->E.A.R.firstErrorOrOpen + ) + let expressionValue = + xyCoords + ->E.R.bind(r => r->XYShape.T.makeFromZipped->E.R2.errMap(XYShape.Error.toString)) + ->E.R2.fmap(r => ReducerInterface_InternalExpressionValue.IEvDistribution( + PointSet(makeDist(r)), + )) + expressionValue + } + let library = [ Function.make( ~name="PointSet.makeContinuous", @@ -90,13 +91,15 @@ module Functionn = { Function.make( ~name="Function.declare", ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", - ~examples=`declareFn({ + ~examples=[ + `declareFn({ fn: {|a,b| a }, inputs: [ {min: 0, max: 100}, {min: 30, max: 50} ] })`, + ], ~isExperimental=true, ~definitions=[ FnDefinition.make( @@ -175,12 +178,11 @@ module DistributionCreation = { (), ) } + let library = [ Function.make( ~name="Normal", - ~examples=`normal(5,1) -normal({p5: 4, p95: 10}) -normal({mean: 5, stdev: 2})`, + ~examples=["normal(5,1)", "normal({p5: 4, p95: 10})", "normal({mean: 5, stdev: 2})"], ~definitions=[ TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), TwoArgDist.makeRecordP5P95("normal", r => @@ -192,9 +194,11 @@ normal({mean: 5, stdev: 2})`, ), Function.make( ~name="Lognormal", - ~examples=`lognormal(0.5, 0.8) -lognormal({p5: 4, p95: 10}) -lognormal({mean: 5, stdev: 2})`, + ~examples=[ + "lognormal(0.5, 0.8)", + "lognormal({p5: 4, p95: 10})", + "lognormal({mean: 5, stdev: 2})" + ], ~definitions=[ TwoArgDist.make("lognormal", twoArgs(SymbolicDist.Lognormal.make)), TwoArgDist.makeRecordP5P95("lognormal", r => @@ -209,14 +213,13 @@ lognormal({mean: 5, stdev: 2})`, ), Function.make( ~name="Uniform", - ~examples=`uniform(10, 12)`, + ~examples=[`uniform(10, 12)`], ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], (), ), Function.make( ~name="Beta", - ~examples=`beta(20, 25) -beta({mean: 0.39, stdev: 0.1})`, + ~examples=[`beta(20, 25)`, `beta({mean: 0.39, stdev: 0.1})`], ~definitions=[ TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make)), TwoArgDist.makeRecordMeanStdev("beta", twoArgs(SymbolicDist.Beta.fromMeanAndStdev)), @@ -225,27 +228,25 @@ beta({mean: 0.39, stdev: 0.1})`, ), Function.make( ~name="Cauchy", - ~examples=`cauchy(5, 1)`, + ~examples=[`cauchy(5, 1)`], ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], (), ), Function.make( ~name="Gamma", - ~examples=`gamma(5, 1)`, + ~examples=[`gamma(5, 1)`], ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], (), ), Function.make( ~name="Logistic", - ~examples=`gamma(5, 1)`, + ~examples=[`logistic(5, 1)`], ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], (), ), Function.make( ~name="To (Distribution)", - ~examples=`5 to 10 -to(5,10) --5 to 5`, + ~examples=[`5 to 10`, `to(5,10)`, `-5 to 5`], ~definitions=[ TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), TwoArgDist.make( @@ -257,66 +258,25 @@ to(5,10) ), Function.make( ~name="Exponential", - ~examples=`exponential(2)`, + ~examples=[`exponential(2)`], ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], (), ), Function.make( ~name="Bernoulli", - ~examples=`bernoulli(0.5)`, + ~examples=[`bernoulli(0.5)`], ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], (), ), Function.make( ~name="PointMass", - ~examples=`pointMass(0.5)`, + ~examples=[`pointMass(0.5)`], ~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)], (), ), ] } -let registryStart = [ - Function.make( - ~name="toContinuousPointSet", - ~description="Converts a set of points to a continuous distribution", - ~examples=`toContinuousPointSet([ - {x: 0, y: 0.1}, - {x: 1, y: 0.2}, - {x: 2, y: 0.15}, - {x: 3, y: 0.1} -])`, - ~definitions=[ - FnDefinition.make( - ~name="toContinuousPointSet", - ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(_, inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), - (), - ), - ], - (), - ), - Function.make( - ~name="toDiscretePointSet", - ~description="Converts a set of points to a discrete distribution", - ~examples=`toDiscretePointSet([ - {x: 0, y: 0.1}, - {x: 1, y: 0.2}, - {x: 2, y: 0.15}, - {x: 3, y: 0.1} -])`, - ~definitions=[ - FnDefinition.make( - ~name="toDiscretePointSet", - ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(_, inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), - (), - ), - ], - (), - ), -] - module Number = { let nameSpace = Some("Number") let requiresNamespace = false From 3f09f5f307711fefd6e790f569cadec151b9fb78 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 14 Jul 2022 17:21:07 -0700 Subject: [PATCH 09/40] Move namespace from fnDefinition to fn --- .../FunctionRegistry_Core.res | 41 ++++--- .../FunctionRegistry_Library.res | 110 ++++++++++++------ 2 files changed, 100 insertions(+), 51 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index c50a8297..f18f493f 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -40,16 +40,20 @@ and frValueDictParam = (string, frValue) and frValueDistOrNumber = FRValueNumber(float) | FRValueDist(DistributionTypes.genericDist) type fnDefinition = { - nameSpace: option, requiresNamespace: bool, name: string, inputs: array, - run: (array, array, GenericDist.env)=> result + run: ( + array, + array, + GenericDist.env, + ) => result, } type function = { name: string, definitions: array, + nameSpace: string, examples: array, description: option, isExperimental: bool, @@ -338,9 +342,8 @@ module FnDefinition = { let toLambda = (t: t) => Reducer_Module.convertOptionToFfiFn(t.name, toFfiFn(t))->Reducer_Module.eLambdaFFIValue - let make = (~nameSpace=None, ~requiresNamespace=true, ~name, ~inputs, ~run, ()): t => { + let make = (~requiresNamespace=true, ~name, ~inputs, ~run, ()): t => { name: name, - nameSpace: nameSpace, requiresNamespace: requiresNamespace, inputs: inputs, run: run, @@ -358,8 +361,17 @@ module Function = { isExperimental: bool, } - let make = (~name, ~definitions, ~examples=?, ~description=?, ~isExperimental=false, ()): t => { + let make = ( + ~name, + ~nameSpace, + ~definitions, + ~examples=?, + ~description=?, + ~isExperimental=false, + (), + ): t => { name: name, + nameSpace: nameSpace, definitions: definitions, examples: examples |> E.O.default([]), isExperimental: isExperimental, @@ -377,7 +389,8 @@ module Function = { module Registry = { let toJson = (r: registry) => r->E.A2.fmap(Function.toJson) - let definitions = (r: registry) => r->E.A2.fmap(d => d.definitions)->E.A.concatMany + let definitionsWithFunctions = (r: registry) => + r->E.A2.fmap(fn => fn.definitions->E.A2.fmap(def => (def, fn)))->E.A.concatMany /* There's a (potential+minor) bug here: If a function definition is called outside of the calls @@ -409,21 +422,17 @@ module Registry = { } } - let allNamespaces = (t: registry) => - t - ->E.A2.fmap(r => r.definitions) - ->Belt.Array.concatMany - ->E.A2.fmap(r => r.nameSpace) - ->E.A.O.concatSomes - ->E.A.uniq + //todo: get namespace from project. + let allNamespaces = (t: registry) => t->E.A2.fmap(r => r.nameSpace)->E.A.uniq let makeModules = (prevBindings: Reducer_Module.t, t: registry): Reducer_Module.t => { let nameSpaces = allNamespaces(t) let nameSpaceBindings = nameSpaces->E.A2.fmap(nameSpace => { - let definitions = t->definitions->E.A2.filter(d => d.nameSpace === Some(nameSpace)) + let definitions = + t->definitionsWithFunctions->E.A2.filter(((_, fn)) => fn.nameSpace === nameSpace) - let newModule = E.A.reduce(definitions, Reducer_Module.emptyStdLib, (acc, d) => { - acc->Reducer_Module.defineFunction(d.name, FnDefinition.toFfiFn(d)) + let newModule = E.A.reduce(definitions, Reducer_Module.emptyStdLib, (acc, (def, _)) => { + acc->Reducer_Module.defineFunction(def.name, FnDefinition.toFfiFn(def)) }) (nameSpace, newModule) }) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 465a5834..1d74f451 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -31,7 +31,7 @@ module Declaration = { } module PointSet = { - let nameSpace = Some("PointSet") + let nameSpace = "PointSet" let requiresNamespace = true let inputsTodist = (inputs: array, makeDist) => { @@ -56,9 +56,9 @@ module PointSet = { let library = [ Function.make( ~name="PointSet.makeContinuous", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace, ~name="makeContinuous", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], @@ -70,9 +70,9 @@ module PointSet = { ), Function.make( ~name="PointSet.makeDiscrete", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace, ~name="makeDiscrete", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], @@ -86,10 +86,11 @@ module PointSet = { } module Functionn = { - let nameSpace = Some("Function") + let nameSpace = "Function" let library = [ Function.make( ~name="Function.declare", + ~nameSpace, ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", ~examples=[ `declareFn({ @@ -103,7 +104,6 @@ module Functionn = { ~isExperimental=true, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace=true, ~name="declare", ~inputs=[Declaration.frType], @@ -119,7 +119,7 @@ module Functionn = { } module DistributionCreation = { - let nameSpace = Some("Dist") + let nameSpace = "Dist" module TwoArgDist = { let process = (~fn, ~env, r) => r @@ -128,7 +128,6 @@ module DistributionCreation = { let make = (name, fn) => { FnDefinition.make( - ~nameSpace, ~requiresNamespace=false, ~name, ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], @@ -139,7 +138,6 @@ module DistributionCreation = { let makeRecordP5P95 = (name, fn) => { FnDefinition.make( - ~nameSpace, ~requiresNamespace=false, ~name, ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], @@ -152,7 +150,6 @@ module DistributionCreation = { let makeRecordMeanStdev = (name, fn) => { FnDefinition.make( ~name, - ~nameSpace, ~requiresNamespace=false, ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], ~run=(_, inputs, env) => @@ -170,7 +167,6 @@ module DistributionCreation = { let make = (name, fn) => FnDefinition.make( - ~nameSpace, ~requiresNamespace=false, ~name, ~inputs=[FRTypeDistOrNumber], @@ -182,6 +178,7 @@ module DistributionCreation = { let library = [ Function.make( ~name="Normal", + ~nameSpace, ~examples=["normal(5,1)", "normal({p5: 4, p95: 10})", "normal({mean: 5, stdev: 2})"], ~definitions=[ TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), @@ -194,10 +191,11 @@ module DistributionCreation = { ), Function.make( ~name="Lognormal", + ~nameSpace, ~examples=[ "lognormal(0.5, 0.8)", "lognormal({p5: 4, p95: 10})", - "lognormal({mean: 5, stdev: 2})" + "lognormal({mean: 5, stdev: 2})", ], ~definitions=[ TwoArgDist.make("lognormal", twoArgs(SymbolicDist.Lognormal.make)), @@ -213,12 +211,14 @@ module DistributionCreation = { ), Function.make( ~name="Uniform", + ~nameSpace, ~examples=[`uniform(10, 12)`], ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], (), ), Function.make( ~name="Beta", + ~nameSpace, ~examples=[`beta(20, 25)`, `beta({mean: 0.39, stdev: 0.1})`], ~definitions=[ TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make)), @@ -228,24 +228,28 @@ module DistributionCreation = { ), Function.make( ~name="Cauchy", + ~nameSpace, ~examples=[`cauchy(5, 1)`], ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], (), ), Function.make( ~name="Gamma", + ~nameSpace, ~examples=[`gamma(5, 1)`], ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], (), ), Function.make( ~name="Logistic", + ~nameSpace, ~examples=[`logistic(5, 1)`], ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], (), ), Function.make( ~name="To (Distribution)", + ~nameSpace, ~examples=[`5 to 10`, `to(5,10)`, `-5 to 5`], ~definitions=[ TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), @@ -258,18 +262,21 @@ module DistributionCreation = { ), Function.make( ~name="Exponential", + ~nameSpace, ~examples=[`exponential(2)`], ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], (), ), Function.make( ~name="Bernoulli", + ~nameSpace, ~examples=[`bernoulli(0.5)`], ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], (), ), Function.make( ~name="PointMass", + ~nameSpace, ~examples=[`pointMass(0.5)`], ~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)], (), @@ -278,13 +285,12 @@ module DistributionCreation = { } module Number = { - let nameSpace = Some("Number") + let nameSpace = "Number" let requiresNamespace = false module NumberToNumber = { let make = (name, fn) => FnDefinition.make( - ~nameSpace, ~requiresNamespace, ~name, ~inputs=[FRTypeNumber], @@ -302,7 +308,6 @@ module Number = { module ArrayNumberDist = { let make = (name, fn) => { FnDefinition.make( - ~nameSpace, ~requiresNamespace=false, ~name, ~inputs=[FRTypeArray(FRTypeNumber)], @@ -329,35 +334,61 @@ module Number = { let library = [ Function.make( ~name="Floor", + ~nameSpace, ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], (), ), Function.make( ~name="Ceiling", + ~nameSpace, ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], (), ), Function.make( ~name="Absolute Value", + ~nameSpace, ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], (), ), - Function.make(~name="Exponent", ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], ()), - Function.make(~name="Log", ~definitions=[NumberToNumber.make("log", Js.Math.log)], ()), + Function.make( + ~name="Exponent", + ~nameSpace, + ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], + (), + ), + Function.make( + ~name="Log", + ~nameSpace, + ~definitions=[NumberToNumber.make("log", Js.Math.log)], + (), + ), Function.make( ~name="Log Base 10", + ~nameSpace, ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], (), ), - Function.make(~name="Log Base 2", ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], ()), - Function.make(~name="Round", ~definitions=[NumberToNumber.make("round", Js.Math.round)], ()), + Function.make( + ~name="Log Base 2", + ~nameSpace, + ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], + (), + ), + Function.make( + ~name="Round", + ~nameSpace, + ~definitions=[NumberToNumber.make("round", Js.Math.round)], + (), + ), Function.make( ~name="Sum", + ~nameSpace, ~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)], (), ), Function.make( ~name="Product", + ~nameSpace, ~definitions=[ ArrayNumberDist.make("product", r => r->E.A.Floats.product->Wrappers.evNumber->Ok), ], @@ -365,21 +396,25 @@ module Number = { ), Function.make( ~name="Min", + ~nameSpace, ~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)], (), ), Function.make( ~name="Max", + ~nameSpace, ~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)], (), ), Function.make( ~name="Mean", + ~nameSpace, ~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)], (), ), Function.make( ~name="Geometric Mean", + ~nameSpace, ~definitions=[ ArrayNumberDist.make("geomean", r => r->E.A.Floats.geomean->Wrappers.evNumber->Ok), ], @@ -387,11 +422,13 @@ module Number = { ), Function.make( ~name="Standard Deviation", + ~nameSpace, ~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)], (), ), Function.make( ~name="Variance", + ~nameSpace, ~definitions=[ ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok), ], @@ -399,6 +436,7 @@ module Number = { ), Function.make( ~name="Sort", + ~nameSpace, ~definitions=[ ArrayNumberDist.make("sort", r => r->E.A.Floats.sort->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok @@ -408,6 +446,7 @@ module Number = { ), Function.make( ~name="Cumulative Sum", + ~nameSpace, ~definitions=[ ArrayNumberDist.make("cumsum", r => r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok @@ -417,6 +456,7 @@ module Number = { ), Function.make( ~name="Cumulative Prod", + ~nameSpace, ~definitions=[ ArrayNumberDist.make("cumprod", r => r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok @@ -426,6 +466,7 @@ module Number = { ), Function.make( ~name="Diff", + ~nameSpace, ~definitions=[ ArrayNumberDist.make("diff", r => r->E.A.Floats.diff->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok @@ -437,7 +478,7 @@ module Number = { } module Dict = { - let nameSpace = Some("Dict") + let nameSpace = "Dict" module Internals = { type t = ReducerInterface_InternalExpressionValue.map @@ -482,9 +523,9 @@ module Dict = { let library = [ Function.make( ~name="merge", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace=true, ~name="merge", ~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)], @@ -502,9 +543,9 @@ module Dict = { //TODO: Change to use new mergeMany() function. Function.make( ~name="mergeMany", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace=true, ~name="mergeMany", ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], @@ -522,9 +563,9 @@ module Dict = { ), Function.make( ~name="keys", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace=true, ~name="keys", ~inputs=[FRTypeDict(FRTypeAny)], @@ -540,9 +581,9 @@ module Dict = { ), Function.make( ~name="values", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace=true, ~name="values", ~inputs=[FRTypeDict(FRTypeAny)], @@ -558,9 +599,9 @@ module Dict = { ), Function.make( ~name="toList", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace=true, ~name="toList", ~inputs=[FRTypeDict(FRTypeAny)], @@ -576,9 +617,9 @@ module Dict = { ), Function.make( ~name="fromList", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace=true, ~name="fromList", ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], @@ -596,7 +637,7 @@ module Dict = { } module List = { - let nameSpace = Some("List") + let nameSpace = "List" let requiresNamespace = true module Internals = { @@ -625,10 +666,10 @@ module List = { let library = [ Function.make( ~name="List.make", + ~nameSpace, ~definitions=[ //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. FnDefinition.make( - ~nameSpace, ~requiresNamespace, ~name="make", ~inputs=[FRTypeNumber, FRTypeAny], @@ -645,9 +686,9 @@ module List = { ), Function.make( ~name="List.upTo", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace, ~name="upTo", ~inputs=[FRTypeNumber, FRTypeNumber], @@ -662,9 +703,9 @@ module List = { ), Function.make( ~name="List.first", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace, ~name="first", ~inputs=[FRTypeArray(FRTypeAny)], @@ -680,9 +721,9 @@ module List = { ), Function.make( ~name="List.last", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace=false, ~name="last", ~inputs=[FRTypeArray(FRTypeAny)], @@ -698,9 +739,9 @@ module List = { ), Function.make( ~name="List.reverse", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace=false, ~name="reverse", ~inputs=[FRTypeArray(FRTypeAny)], @@ -718,7 +759,7 @@ module List = { } module Scoring = { - let nameSpace = Some("Dist") + let nameSpace = "Dist" let requiresNamespace = false let runScoring = (estimate, answer, prior, env) => { @@ -730,9 +771,9 @@ module Scoring = { let library = [ Function.make( ~name="logScore", + ~nameSpace, ~definitions=[ FnDefinition.make( - ~nameSpace, ~requiresNamespace, ~name="logScore", ~inputs=[ @@ -764,7 +805,6 @@ module Scoring = { ), FnDefinition.make( ~name="logScore", - ~nameSpace, ~requiresNamespace, ~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])], ~run=(_, inputs, env) => { @@ -784,10 +824,10 @@ module Scoring = { ), Function.make( ~name="klDivergence", + ~nameSpace, ~definitions=[ FnDefinition.make( ~name="klDivergence", - ~nameSpace, ~requiresNamespace, ~inputs=[FRTypeDist, FRTypeDist], ~run=(_, inputs, env) => { From 8839f1d9c727f347b873ef79a86926c28e8bd413 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 14 Jul 2022 22:14:23 -0700 Subject: [PATCH 10/40] Added FunctionRegistry test and got simple polymorphism working --- .../__tests__/FunctionRegistry_test.res | 82 +++++++++++++++++++ packages/squiggle-lang/package.json | 1 + .../FunctionRegistry_Core.res | 46 +++++++++-- .../SquiggleLibrary/SquiggleLibrary_Math.res | 1 + 4 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/FunctionRegistry_test.res diff --git a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res new file mode 100644 index 00000000..e976f7b1 --- /dev/null +++ b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res @@ -0,0 +1,82 @@ +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module ExpressionT = Reducer_Expression_T +module Module = Reducer_Module +module Bindings = Reducer_Module +module ErrorValue = Reducer_ErrorValue + +open Jest +open Expect + +// ---------------------- +// --- Start of Module File +// ---------------------- + +module FooImplementation = { + open FunctionRegistry_Core + open FunctionRegistry_Helpers + + let library = [ + Function.make( + ~name="add", + ~nameSpace="Foo", + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=false, + ~name="add", + ~inputs=[FRTypeNumber, FRTypeNumber], + ~run=(_, inputs, _) => + switch inputs { + | [FRValueNumber(a), FRValueNumber(b)] => Ok(Wrappers.evNumber(a +. b)) + | _ => Error("False") + }, + (), + ), + FnDefinition.make( + ~requiresNamespace=true, + ~name="add", + ~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber], + ~run=(_, inputs, _) => + switch inputs { + | [FRValueNumber(a), FRValueNumber(b), FRValueNumber(c)] => + Ok(Wrappers.evNumber(a +. b +. c)) + | _ => Error("False") + }, + (), + ), + ], + (), + ), + ] +} + +let makeBindings = (previousBindings: Bindings.t): Bindings.t => + previousBindings->FunctionRegistry_Core.Registry.makeModules(FooImplementation.library) + +let stdLibWithFoo = Bindings.emptyBindings->makeBindings + +let evalWithFoo = sourceCode => + Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr => + Reducer_Expression.reduceExpression( + expr, + stdLibWithFoo, + InternalExpressionValue.defaultEnvironment, + ) + ) + +let evalToStringResultWithFoo = sourceCode => + evalWithFoo(sourceCode)->InternalExpressionValue.toStringResult + +describe("Module", () => { + test("add(1,2)", () => { + let result = evalToStringResultWithFoo("Foo.add(1,2)") + expect(result)->toEqual("Ok(3)") + }) + test("add(1,2,3)", () => { + let result = evalToStringResultWithFoo("Foo.add(1,2,3)") + expect(result)->toEqual("Ok(6)") + }) + test("add(1,2,3,5)", () => { + let result = evalToStringResultWithFoo("Foo.add(1,2,3,5)") + expect(result)->toEqual("Ok(6)") + }) +}) \ No newline at end of file diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index b2067205..ba6449ce 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -15,6 +15,7 @@ "start": "rescript build -w -with-deps", "clean": "rescript clean && rm -rf dist", "test:reducer": "jest __tests__/Reducer*/", + "test:reducer2": "jest __tests__/FunctionRegistry_test", "benchmark": "ts-node benchmark/conversion_tests.ts", "test": "jest", "test:ts": "jest __tests__/TS/", diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index f18f493f..e0ef4441 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -328,6 +328,14 @@ module FnDefinition = { t.name ++ `(${inputs})` } + let isMatch = (t: t, args: array) => { + let argValues = FRType.matchWithExpressionValueArray(t.inputs, args) + switch argValues { + | Some(values) => true + | None => false + } + } + let run = (t: t, args: array, env: GenericDist.env) => { let argValues = FRType.matchWithExpressionValueArray(t.inputs, args) switch argValues { @@ -387,6 +395,32 @@ module Function = { } } +module NameSpace = { + type t = {name: string, functions: array} + let definitions = (t: t) => t.functions->E.A2.fmap(f => f.definitions)->E.A.concatMany + let uniqueFnNames = (t: t) => definitions(t)->E.A2.fmap(r => r.name)->E.A.uniq + let nameToDefinitions = (t: t, name: string) => definitions(t)->E.A2.filter(r => r.name == name) + + //todo: It could be good to set a warning if two definitions are both valid, but I don't expect this often. + let nameFfiFn = (t: t, name: string): Reducer_Expression_T.optionFfiFn => { + (args, environment) => { + let definitions = + nameToDefinitions(t, name)->E.A2.fmap((def, ()) => + FnDefinition.isMatch(def, args) + ? FnDefinition.run(def, args, environment) |> E.R.toOption + : None + ) + E.A.O.firstSomeFn(definitions) + } + } + + let toModule = (t: t): Reducer_Module.t => + E.A.reduce(uniqueFnNames(t), Reducer_Module.emptyStdLib, (acc, uniqueName) => { + let relevantDefinitions = nameFfiFn(t, uniqueName) + acc->Reducer_Module.defineFunction(uniqueName, relevantDefinitions) + }) +} + module Registry = { let toJson = (r: registry) => r->E.A2.fmap(Function.toJson) let definitionsWithFunctions = (r: registry) => @@ -428,13 +462,11 @@ module Registry = { let makeModules = (prevBindings: Reducer_Module.t, t: registry): Reducer_Module.t => { let nameSpaces = allNamespaces(t) let nameSpaceBindings = nameSpaces->E.A2.fmap(nameSpace => { - let definitions = - t->definitionsWithFunctions->E.A2.filter(((_, fn)) => fn.nameSpace === nameSpace) - - let newModule = E.A.reduce(definitions, Reducer_Module.emptyStdLib, (acc, (def, _)) => { - acc->Reducer_Module.defineFunction(def.name, FnDefinition.toFfiFn(def)) - }) - (nameSpace, newModule) + let foo: NameSpace.t = { + name: nameSpace, + functions: t->E.A2.filter(r => r.nameSpace == nameSpace), + } + (nameSpace, NameSpace.toModule(foo)) }) E.A.reduce(nameSpaceBindings, prevBindings, (acc, (name, fn)) => acc->Reducer_Module.defineModule(name, fn) diff --git a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res index 436ed1fe..b7b925ed 100644 --- a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res +++ b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res @@ -19,6 +19,7 @@ let mathBindings: Bindings.t = ->E.A2.fmap(((name, v)) => (name, ReducerInterface_InternalExpressionValue.IEvNumber(v))) ->Bindings.fromArray +//TODO: This should be in a different place. let makeBindings = (previousBindings: Bindings.t): Bindings.t => previousBindings ->Bindings.defineModule("Math", mathBindings) From 9d5aaf43a8375a1c576a64658f966f2d09a46010 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 15 Jul 2022 19:18:36 -0700 Subject: [PATCH 11/40] Simple tests for fake FunctionRegistry output types --- .../__tests__/FunctionRegistry_test.res | 83 +++++++++++-------- .../FunctionRegistry_Core.res | 4 + .../FunctionRegistry_Library.res | 78 ++++++++--------- 3 files changed, 91 insertions(+), 74 deletions(-) diff --git a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res index e976f7b1..47d3005a 100644 --- a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res +++ b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res @@ -15,38 +15,40 @@ module FooImplementation = { open FunctionRegistry_Core open FunctionRegistry_Helpers - let library = [ - Function.make( - ~name="add", - ~nameSpace="Foo", - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=false, - ~name="add", - ~inputs=[FRTypeNumber, FRTypeNumber], - ~run=(_, inputs, _) => - switch inputs { - | [FRValueNumber(a), FRValueNumber(b)] => Ok(Wrappers.evNumber(a +. b)) - | _ => Error("False") - }, - (), - ), - FnDefinition.make( - ~requiresNamespace=true, - ~name="add", - ~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber], - ~run=(_, inputs, _) => - switch inputs { - | [FRValueNumber(a), FRValueNumber(b), FRValueNumber(c)] => - Ok(Wrappers.evNumber(a +. b +. c)) - | _ => Error("False") - }, - (), - ), - ], - (), - ), - ] + let fn = Function.make( + ~name="add", + ~nameSpace="Foo", + ~examples=["Foo.add(1, 2)", "Foo.add(1, 2, 3)"], + ~output=EvtNumber, + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=false, + ~name="add", + ~inputs=[FRTypeNumber, FRTypeNumber], + ~run=(_, inputs, _) => + switch inputs { + | [FRValueNumber(a), FRValueNumber(b)] => Ok(Wrappers.evNumber(a +. b)) + | _ => Error("False") + }, + (), + ), + FnDefinition.make( + ~requiresNamespace=true, + ~name="add", + ~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber], + ~run=(_, inputs, _) => + switch inputs { + | [FRValueNumber(a), FRValueNumber(b), FRValueNumber(c)] => + Ok(Wrappers.evNumber(a +. b +. c)) + | _ => Error("False") + }, + (), + ), + ], + (), + ) + + let library = [fn] } let makeBindings = (previousBindings: Bindings.t): Bindings.t => @@ -75,8 +77,19 @@ describe("Module", () => { let result = evalToStringResultWithFoo("Foo.add(1,2,3)") expect(result)->toEqual("Ok(6)") }) - test("add(1,2,3,5)", () => { - let result = evalToStringResultWithFoo("Foo.add(1,2,3,5)") - expect(result)->toEqual("Ok(6)") +}) + +describe("Fn auto-testing", () => { + let items = FooImplementation.fn.examples->E.A.to_list + + testAll("tests of validity", items, r => { + expect(r->evalWithFoo->E.R.isOk)->toEqual(true) + }) + + testAll("tests of type", items, r => { + let responseType = + r->evalWithFoo->E.R2.fmap(ReducerInterface_InternalExpressionValue.valueToValueType) + let expectedOutputType = FooImplementation.fn.output |> E.O.toExn("") + expect(responseType)->toEqual(Ok(expectedOutputType)) }) }) \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index e0ef4441..d2d2a080 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -1,4 +1,5 @@ type internalExpressionValue = ReducerInterface_InternalExpressionValue.t +type internalExpressionValueType = ReducerInterface_InternalExpressionValue.internalExpressionValueType /* Function Registry "Type". A type, without any other information. @@ -54,6 +55,7 @@ type function = { name: string, definitions: array, nameSpace: string, + output: option, examples: array, description: option, isExperimental: bool, @@ -374,6 +376,7 @@ module Function = { ~nameSpace, ~definitions, ~examples=?, + ~output=?, ~description=?, ~isExperimental=false, (), @@ -381,6 +384,7 @@ module Function = { name: name, nameSpace: nameSpace, definitions: definitions, + output: output, examples: examples |> E.O.default([]), isExperimental: isExperimental, description: description, diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 1d74f451..6543cbc9 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -55,7 +55,7 @@ module PointSet = { let library = [ Function.make( - ~name="PointSet.makeContinuous", + ~name="makeContinuous", ~nameSpace, ~definitions=[ FnDefinition.make( @@ -69,7 +69,7 @@ module PointSet = { (), ), Function.make( - ~name="PointSet.makeDiscrete", + ~name="makeDiscrete", ~nameSpace, ~definitions=[ FnDefinition.make( @@ -89,7 +89,7 @@ module Functionn = { let nameSpace = "Function" let library = [ Function.make( - ~name="Function.declare", + ~name="declare", ~nameSpace, ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", ~examples=[ @@ -177,7 +177,7 @@ module DistributionCreation = { let library = [ Function.make( - ~name="Normal", + ~name="normal", ~nameSpace, ~examples=["normal(5,1)", "normal({p5: 4, p95: 10})", "normal({mean: 5, stdev: 2})"], ~definitions=[ @@ -190,7 +190,7 @@ module DistributionCreation = { (), ), Function.make( - ~name="Lognormal", + ~name="lognormal", ~nameSpace, ~examples=[ "lognormal(0.5, 0.8)", @@ -210,14 +210,14 @@ module DistributionCreation = { (), ), Function.make( - ~name="Uniform", + ~name="uniform", ~nameSpace, ~examples=[`uniform(10, 12)`], ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], (), ), Function.make( - ~name="Beta", + ~name="beta", ~nameSpace, ~examples=[`beta(20, 25)`, `beta({mean: 0.39, stdev: 0.1})`], ~definitions=[ @@ -227,28 +227,28 @@ module DistributionCreation = { (), ), Function.make( - ~name="Cauchy", + ~name="cauchy", ~nameSpace, ~examples=[`cauchy(5, 1)`], ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], (), ), Function.make( - ~name="Gamma", + ~name="gamma", ~nameSpace, ~examples=[`gamma(5, 1)`], ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], (), ), Function.make( - ~name="Logistic", + ~name="logistic", ~nameSpace, ~examples=[`logistic(5, 1)`], ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], (), ), Function.make( - ~name="To (Distribution)", + ~name="to (distribution)", ~nameSpace, ~examples=[`5 to 10`, `to(5,10)`, `-5 to 5`], ~definitions=[ @@ -261,21 +261,21 @@ module DistributionCreation = { (), ), Function.make( - ~name="Exponential", + ~name="exponential", ~nameSpace, ~examples=[`exponential(2)`], ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], (), ), Function.make( - ~name="Bernoulli", + ~name="bernoulli", ~nameSpace, ~examples=[`bernoulli(0.5)`], ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], (), ), Function.make( - ~name="PointMass", + ~name="pointMass", ~nameSpace, ~examples=[`pointMass(0.5)`], ~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)], @@ -333,61 +333,61 @@ module Number = { let library = [ Function.make( - ~name="Floor", + ~name="floor", ~nameSpace, ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], (), ), Function.make( - ~name="Ceiling", + ~name="ceiling", ~nameSpace, ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], (), ), Function.make( - ~name="Absolute Value", + ~name="absolute value", ~nameSpace, ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], (), ), Function.make( - ~name="Exponent", + ~name="exponent", ~nameSpace, ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], (), ), Function.make( - ~name="Log", + ~name="log", ~nameSpace, ~definitions=[NumberToNumber.make("log", Js.Math.log)], (), ), Function.make( - ~name="Log Base 10", + ~name="log base 10", ~nameSpace, ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], (), ), Function.make( - ~name="Log Base 2", + ~name="log base 2", ~nameSpace, ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], (), ), Function.make( - ~name="Round", + ~name="round", ~nameSpace, ~definitions=[NumberToNumber.make("round", Js.Math.round)], (), ), Function.make( - ~name="Sum", + ~name="sum", ~nameSpace, ~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)], (), ), Function.make( - ~name="Product", + ~name="product", ~nameSpace, ~definitions=[ ArrayNumberDist.make("product", r => r->E.A.Floats.product->Wrappers.evNumber->Ok), @@ -395,25 +395,25 @@ module Number = { (), ), Function.make( - ~name="Min", + ~name="min", ~nameSpace, ~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)], (), ), Function.make( - ~name="Max", + ~name="max", ~nameSpace, ~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)], (), ), Function.make( - ~name="Mean", + ~name="mean", ~nameSpace, ~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)], (), ), Function.make( - ~name="Geometric Mean", + ~name="geometric mean", ~nameSpace, ~definitions=[ ArrayNumberDist.make("geomean", r => r->E.A.Floats.geomean->Wrappers.evNumber->Ok), @@ -421,13 +421,13 @@ module Number = { (), ), Function.make( - ~name="Standard Deviation", + ~name="standard deviation", ~nameSpace, ~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)], (), ), Function.make( - ~name="Variance", + ~name="variance", ~nameSpace, ~definitions=[ ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok), @@ -435,7 +435,7 @@ module Number = { (), ), Function.make( - ~name="Sort", + ~name="sort", ~nameSpace, ~definitions=[ ArrayNumberDist.make("sort", r => @@ -445,7 +445,7 @@ module Number = { (), ), Function.make( - ~name="Cumulative Sum", + ~name="cumulative sum", ~nameSpace, ~definitions=[ ArrayNumberDist.make("cumsum", r => @@ -455,7 +455,7 @@ module Number = { (), ), Function.make( - ~name="Cumulative Prod", + ~name="cumulative prod", ~nameSpace, ~definitions=[ ArrayNumberDist.make("cumprod", r => @@ -465,7 +465,7 @@ module Number = { (), ), Function.make( - ~name="Diff", + ~name="diff", ~nameSpace, ~definitions=[ ArrayNumberDist.make("diff", r => @@ -665,7 +665,7 @@ module List = { let library = [ Function.make( - ~name="List.make", + ~name="make", ~nameSpace, ~definitions=[ //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. @@ -685,7 +685,7 @@ module List = { (), ), Function.make( - ~name="List.upTo", + ~name="upTo", ~nameSpace, ~definitions=[ FnDefinition.make( @@ -702,7 +702,7 @@ module List = { (), ), Function.make( - ~name="List.first", + ~name="first", ~nameSpace, ~definitions=[ FnDefinition.make( @@ -720,7 +720,7 @@ module List = { (), ), Function.make( - ~name="List.last", + ~name="last", ~nameSpace, ~definitions=[ FnDefinition.make( @@ -738,7 +738,7 @@ module List = { (), ), Function.make( - ~name="List.reverse", + ~name="reverse", ~nameSpace, ~definitions=[ FnDefinition.make( From e3ef7a304885cb93c8f5ff1665f43dfc7da4cf04 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 15 Jul 2022 19:47:57 -0700 Subject: [PATCH 12/40] Added examples to most items in function registry library --- .../FunctionRegistry_Library.res | 120 +++++++++++++----- 1 file changed, 87 insertions(+), 33 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 6543cbc9..5d68c7b9 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -120,6 +120,12 @@ module Functionn = { module DistributionCreation = { let nameSpace = "Dist" + let output = ReducerInterface_InternalExpressionValue.EvtDistribution + + let fnMake = (~name, ~examples, ~definitions) => { + Function.make(~name, ~nameSpace, ~output, ~examples, ~definitions, ()) + } + module TwoArgDist = { let process = (~fn, ~env, r) => r @@ -176,9 +182,8 @@ module DistributionCreation = { } let library = [ - Function.make( + fnMake( ~name="normal", - ~nameSpace, ~examples=["normal(5,1)", "normal({p5: 4, p95: 10})", "normal({mean: 5, stdev: 2})"], ~definitions=[ TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), @@ -187,11 +192,9 @@ module DistributionCreation = { ), TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), ], - (), ), - Function.make( + fnMake( ~name="lognormal", - ~nameSpace, ~examples=[ "lognormal(0.5, 0.8)", "lognormal({p5: 4, p95: 10})", @@ -207,49 +210,37 @@ module DistributionCreation = { twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev), ), ], - (), ), - Function.make( + fnMake( ~name="uniform", - ~nameSpace, ~examples=[`uniform(10, 12)`], ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], - (), ), - Function.make( + fnMake( ~name="beta", - ~nameSpace, ~examples=[`beta(20, 25)`, `beta({mean: 0.39, stdev: 0.1})`], ~definitions=[ TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make)), TwoArgDist.makeRecordMeanStdev("beta", twoArgs(SymbolicDist.Beta.fromMeanAndStdev)), ], - (), ), - Function.make( + fnMake( ~name="cauchy", - ~nameSpace, ~examples=[`cauchy(5, 1)`], ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], - (), ), - Function.make( + fnMake( ~name="gamma", - ~nameSpace, ~examples=[`gamma(5, 1)`], ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], - (), ), - Function.make( + fnMake( ~name="logistic", - ~nameSpace, ~examples=[`logistic(5, 1)`], ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], - (), ), - Function.make( + fnMake( ~name="to (distribution)", - ~nameSpace, ~examples=[`5 to 10`, `to(5,10)`, `-5 to 5`], ~definitions=[ TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), @@ -258,28 +249,21 @@ module DistributionCreation = { twoArgs(SymbolicDist.From90thPercentile.make), ), ], - (), ), - Function.make( + fnMake( ~name="exponential", - ~nameSpace, ~examples=[`exponential(2)`], ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], - (), ), - Function.make( + fnMake( ~name="bernoulli", - ~nameSpace, ~examples=[`bernoulli(0.5)`], ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], - (), ), - Function.make( + fnMake( ~name="pointMass", - ~nameSpace, ~examples=[`pointMass(0.5)`], ~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)], - (), ), ] } @@ -335,60 +319,80 @@ module Number = { Function.make( ~name="floor", ~nameSpace, + ~output=EvtNumber, + ~examples=[`floor(3.5)`], ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], (), ), Function.make( ~name="ceiling", ~nameSpace, + ~output=EvtNumber, + ~examples=[`ceiling(3.5)`], ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], (), ), Function.make( ~name="absolute value", ~nameSpace, + ~output=EvtNumber, + ~examples=[`abs(3.5)`], ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], (), ), Function.make( ~name="exponent", ~nameSpace, + ~output=EvtNumber, + ~examples=[`exp(3.5)`], ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], (), ), Function.make( ~name="log", ~nameSpace, + ~output=EvtNumber, + ~examples=[`log(3.5)`], ~definitions=[NumberToNumber.make("log", Js.Math.log)], (), ), Function.make( ~name="log base 10", ~nameSpace, + ~output=EvtNumber, + ~examples=[`log10(3.5)`], ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], (), ), Function.make( ~name="log base 2", ~nameSpace, + ~output=EvtNumber, + ~examples=[`log2(3.5)`], ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], (), ), Function.make( ~name="round", ~nameSpace, + ~output=EvtNumber, + ~examples=[`round(3.5)`], ~definitions=[NumberToNumber.make("round", Js.Math.round)], (), ), Function.make( ~name="sum", ~nameSpace, + ~output=EvtNumber, + ~examples=[`sum([3,5,2])`], ~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)], (), ), Function.make( ~name="product", ~nameSpace, + ~output=EvtNumber, + ~examples=[`product([3,5,2])`], ~definitions=[ ArrayNumberDist.make("product", r => r->E.A.Floats.product->Wrappers.evNumber->Ok), ], @@ -397,24 +401,32 @@ module Number = { Function.make( ~name="min", ~nameSpace, + ~output=EvtNumber, + ~examples=[`min([3,5,2])`], ~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)], (), ), Function.make( ~name="max", ~nameSpace, + ~output=EvtNumber, + ~examples=[`max([3,5,2])`], ~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)], (), ), Function.make( ~name="mean", ~nameSpace, + ~output=EvtNumber, + ~examples=[`mean([3,5,2])`], ~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)], (), ), Function.make( ~name="geometric mean", ~nameSpace, + ~output=EvtNumber, + ~examples=[`geomean([3,5,2])`], ~definitions=[ ArrayNumberDist.make("geomean", r => r->E.A.Floats.geomean->Wrappers.evNumber->Ok), ], @@ -423,12 +435,16 @@ module Number = { Function.make( ~name="standard deviation", ~nameSpace, + ~output=EvtNumber, + ~examples=[`stdev([3,5,2,3,5])`], ~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)], (), ), Function.make( ~name="variance", ~nameSpace, + ~output=EvtNumber, + ~examples=[`variance([3,5,2,3,5])`], ~definitions=[ ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok), ], @@ -437,6 +453,8 @@ module Number = { Function.make( ~name="sort", ~nameSpace, + ~output=EvtArray, + ~examples=[`sort([3,5,2,3,5])`], ~definitions=[ ArrayNumberDist.make("sort", r => r->E.A.Floats.sort->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok @@ -447,6 +465,8 @@ module Number = { Function.make( ~name="cumulative sum", ~nameSpace, + ~output=EvtArray, + ~examples=[`cumsum([3,5,2,3,5])`], ~definitions=[ ArrayNumberDist.make("cumsum", r => r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok @@ -457,6 +477,8 @@ module Number = { Function.make( ~name="cumulative prod", ~nameSpace, + ~output=EvtArray, + ~examples=[`cumprod([3,5,2,3,5])`], ~definitions=[ ArrayNumberDist.make("cumprod", r => r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok @@ -467,6 +489,8 @@ module Number = { Function.make( ~name="diff", ~nameSpace, + ~output=EvtArray, + ~examples=[`diff([3,5,2,3,5])`], ~definitions=[ ArrayNumberDist.make("diff", r => r->E.A.Floats.diff->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok @@ -524,6 +548,8 @@ module Dict = { Function.make( ~name="merge", ~nameSpace, + ~output=EvtRecord, + ~examples=[`Dict.merge({a: 1, b: 2}, {c: 3, d: 4})`], ~definitions=[ FnDefinition.make( ~requiresNamespace=true, @@ -544,6 +570,8 @@ module Dict = { Function.make( ~name="mergeMany", ~nameSpace, + ~output=EvtRecord, + ~examples=[`Dict.mergeMany([{a: 1, b: 2}, {c: 3, d: 4}])`], ~definitions=[ FnDefinition.make( ~requiresNamespace=true, @@ -564,6 +592,8 @@ module Dict = { Function.make( ~name="keys", ~nameSpace, + ~output=EvtArray, + ~examples=[`Dict.keys({a: 1, b: 2})`], ~definitions=[ FnDefinition.make( ~requiresNamespace=true, @@ -582,6 +612,8 @@ module Dict = { Function.make( ~name="values", ~nameSpace, + ~output=EvtArray, + ~examples=[`Dict.values({a: 1, b: 2})`], ~definitions=[ FnDefinition.make( ~requiresNamespace=true, @@ -600,6 +632,8 @@ module Dict = { Function.make( ~name="toList", ~nameSpace, + ~output=EvtArray, + ~examples=[`Dict.toList({a: 1, b: 2})`], ~definitions=[ FnDefinition.make( ~requiresNamespace=true, @@ -618,6 +652,8 @@ module Dict = { Function.make( ~name="fromList", ~nameSpace, + ~output=EvtRecord, + ~examples=[`Dict.fromList({a: 1, b: 2})`], ~definitions=[ FnDefinition.make( ~requiresNamespace=true, @@ -667,6 +703,8 @@ module List = { Function.make( ~name="make", ~nameSpace, + ~output=EvtArray, + ~examples=[`List.make(2, "testValue")`], ~definitions=[ //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. FnDefinition.make( @@ -687,6 +725,8 @@ module List = { Function.make( ~name="upTo", ~nameSpace, + ~output=EvtArray, + ~examples=[`List.upTo(1,4)`], ~definitions=[ FnDefinition.make( ~requiresNamespace, @@ -704,6 +744,7 @@ module List = { Function.make( ~name="first", ~nameSpace, + ~examples=[`List.first([1,4,5])`], ~definitions=[ FnDefinition.make( ~requiresNamespace, @@ -722,6 +763,7 @@ module List = { Function.make( ~name="last", ~nameSpace, + ~examples=[`List.last([1,4,5])`], ~definitions=[ FnDefinition.make( ~requiresNamespace=false, @@ -740,6 +782,8 @@ module List = { Function.make( ~name="reverse", ~nameSpace, + ~output=EvtArray, + ~examples=[`List.reverse([1,4,5])`], ~definitions=[ FnDefinition.make( ~requiresNamespace=false, @@ -772,6 +816,12 @@ module Scoring = { Function.make( ~name="logScore", ~nameSpace, + ~output=EvtNumber, + ~examples=[ + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}, prior: normal(5.5,3)})", + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}})", + "Dist.logScore({estimate: normal(5,2), answer: 4.5})", + ], ~definitions=[ FnDefinition.make( ~requiresNamespace, @@ -825,6 +875,10 @@ module Scoring = { Function.make( ~name="klDivergence", ~nameSpace, + ~output=EvtNumber, + ~examples=[ + "Dist.klDivergence(normal(5,2), normal(5,1.5)", + ], ~definitions=[ FnDefinition.make( ~name="klDivergence", From 4522b46900b48ecbb9c9cf086a40eb8efecccbd5 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Fri, 15 Jul 2022 23:18:39 +0200 Subject: [PATCH 13/40] basic type compiler --- .../Reducer_Type_Compile_test.res | 62 +++++++++++++++++++ .../Reducer_Dispatch_BuiltIn.res | 2 +- .../rescript/Reducer/Reducer_Exception.res | 4 +- .../Reducer_Type/Reducer_Type_Compile.res | 36 +++++++++++ .../Reducer/Reducer_Type/Reducer_Type_T.res | 54 +++++++++++++--- .../Reducer_Type/Reducer_Type_TypeBuilder.res | 16 ++--- .../Reducer_Type/Reducer_Type_TypeChecker.res | 30 +++------ 7 files changed, 160 insertions(+), 44 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res create mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res new file mode 100644 index 00000000..3f97ca3f --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res @@ -0,0 +1,62 @@ +module Expression = Reducer_Expression +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Module = Reducer_Module +module T = Reducer_Type_T +module TypeCompile = Reducer_Type_Compile + +open Jest +open Expect + +let myIevEval = (aTypeSourceCode: string) => + TypeCompile.ievFromTypeExpression(aTypeSourceCode, Expression.reduceExpression) +let myIevEvalToString = (aTypeSourceCode: string) => + myIevEval(aTypeSourceCode)->InternalExpressionValue.toStringResult + +let myIevExpectEqual = (aTypeSourceCode, answer) => + expect(myIevEvalToString(aTypeSourceCode))->toEqual(answer) + +let _myIevTest = (test, aTypeSourceCode, answer) => + test(aTypeSourceCode, () => myIevExpectEqual(aTypeSourceCode, answer)) + +let myTypeEval = (aTypeSourceCode: string) => + TypeCompile.fromTypeExpression(aTypeSourceCode, Expression.reduceExpression) +let myTypeEvalToString = (aTypeSourceCode: string) => myTypeEval(aTypeSourceCode)->T.toStringResult + +let myTypeExpectEqual = (aTypeSourceCode, answer) => + expect(myTypeEvalToString(aTypeSourceCode))->toEqual(answer) + +let _myTypeTest = (test, aTypeSourceCode, answer) => + test(aTypeSourceCode, () => myTypeExpectEqual(aTypeSourceCode, answer)) + +let myIevTest = (aTypeSourceCode, answer) => _myIevTest(test, aTypeSourceCode, answer) +let myTypeTest = (aTypeSourceCode, answer) => _myTypeTest(test, aTypeSourceCode, answer) +module MySkip = { + let myIevTest = (aTypeSourceCode, answer) => _myIevTest(Skip.test, aTypeSourceCode, answer) + let myTypeTest = (aTypeSourceCode, answer) => _myTypeTest(Skip.test, aTypeSourceCode, answer) +} +module MyOnly = { + let myIevTest = (aTypeSourceCode, answer) => _myIevTest(Only.test, aTypeSourceCode, answer) + let myTypeTest = (aTypeSourceCode, answer) => _myTypeTest(Only.test, aTypeSourceCode, answer) +} + +// | ItTypeIdentifier(string) +myTypeTest("number", "number") +myTypeTest("(number)", "number") +// | ItModifiedType({modifiedType: iType}) +myIevTest("number<-min(0)", "Ok({min: 0,typeIdentifier: #number,typeTag: 'typeIdentifier'})") +myTypeTest("number<-min(0)", "number<-min(0)") +// | ItTypeOr({typeOr: array}) +myTypeTest("number | string", "(number | string)") +// | ItTypeFunction({inputs: array, output: iType}) +myTypeTest("number => number => number", "(number => number => number)") +// | ItTypeArray({element: iType}) +myIevTest("[number]", "Ok({element: #number,typeTag: 'typeArray'})") +myTypeTest("[number]", "[number]") +// | ItTypeTuple({elements: array}) +myTypeTest("[number, string]", "[number, string]") +// | ItTypeRecord({properties: Belt.Map.String.t}) +myIevTest( + "{age: number, name: string}", + "Ok({properties: {age: #number,name: #string},typeTag: 'typeRecord'})", +) +myTypeTest("{age: number, name: string}", "{age: number, name: string}") 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 484b0acb..07766aca 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 @@ -198,7 +198,7 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce | ("$_typeFunction_$", [IEvArray(arr)]) => TypeBuilder.typeFunction(arr) | ("$_typeTuple_$", [IEvArray(elems)]) => TypeBuilder.typeTuple(elems) | ("$_typeArray_$", [elem]) => TypeBuilder.typeArray(elem) - | ("$_typeRecord_$", [IEvArray(arrayOfPairs)]) => TypeBuilder.typeRecord(arrayOfPairs) + | ("$_typeRecord_$", [IEvRecord(propertyMap)]) => TypeBuilder.typeRecord(propertyMap) | ("concat", [IEvArray(aValueArray), IEvArray(bValueArray)]) => doAddArray(aValueArray, bValueArray) | ("concat", [IEvString(aValueString), IEvString(bValueString)]) => diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Exception.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Exception.res index d7ca335c..14db0843 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Exception.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Exception.res @@ -1,3 +1,3 @@ -// There are switch stament cases in the code which are impossible to reach by design. +// There are switch statement cases in the code which are impossible to reach by design. // ImpossibleException is a sign of programming error. -exception ImpossibleException +exception ImpossibleException(string) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res new file mode 100644 index 00000000..c7a776b7 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res @@ -0,0 +1,36 @@ +module ErrorValue = Reducer_ErrorValue +module ExpressionT = Reducer_Expression_T +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Module = Reducer_Module +module T = Reducer_Type_T + +let ievFromTypeExpression = ( + typeExpressionSourceCode: string, + reducerFn: ExpressionT.reducerFn, +): result => { + let sIndex = "compiled" + let sourceCode = `type ${sIndex}=${typeExpressionSourceCode}` + Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr => { + let rContext = reducerFn(expr, Module.emptyBindings, InternalExpressionValue.defaultEnvironment) + Belt.Result.map(rContext, context => + switch context { + | IEvModule(nameSpace) => + switch Module.getType(nameSpace, sIndex) { + | Some(value) => value + | None => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-none")) + } + | _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-raise")) + } + ) + }) +} + +let fromTypeExpression = ( + typeExpressionSourceCode: string, + reducerFn: ExpressionT.reducerFn, +): result => { + ievFromTypeExpression( + (typeExpressionSourceCode: string), + (reducerFn: ExpressionT.reducerFn), + )->Belt.Result.map(T.fromIEvValue) +} diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res index 9b847ca7..0e3b240d 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res @@ -3,13 +3,41 @@ open InternalExpressionValue type rec iType = | ItTypeIdentifier(string) - | ItModifiedType({modifiedType: iType}) + | ItModifiedType({modifiedType: iType, modifiers: Belt.Map.String.t}) | ItTypeOr({typeOr: array}) | ItTypeFunction({inputs: array, output: iType}) | ItTypeArray({element: iType}) | ItTypeTuple({elements: array}) | ItTypeRecord({properties: Belt.Map.String.t}) +type t = iType + +let rec toString = (t: t): string => { + switch t { + | ItTypeIdentifier(s) => s + | ItModifiedType({modifiedType, modifiers}) => + `${toString(modifiedType)}${modifiers->Belt.Map.String.reduce("", (acc, k, v) => + Js.String2.concatMany(acc, ["<-", k, "(", InternalExpressionValue.toString(v), ")"]) + )}` + | ItTypeOr({typeOr}) => `(${Js.Array2.map(typeOr, toString)->Js.Array2.joinWith(" | ")})` + | ItTypeFunction({inputs, output}) => + `(${inputs->Js.Array2.map(toString)->Js.Array2.joinWith(" => ")} => ${toString(output)})` + | ItTypeArray({element}) => `[${toString(element)}]` + | ItTypeTuple({elements}) => `[${Js.Array2.map(elements, toString)->Js.Array2.joinWith(", ")}]` + | ItTypeRecord({properties}) => + `{${properties + ->Belt.Map.String.toArray + ->Js.Array2.map(((k, v)) => Js.String2.concatMany(k, [": ", toString(v)])) + ->Js.Array2.joinWith(", ")}}` + } +} + +let toStringResult = (rt: result) => + switch rt { + | Ok(t) => toString(t) + | Error(e) => ErrorValue.errorToString(e) + } + let rec fromTypeMap = typeMap => { let default = IEvString("") let evTypeTag: InternalExpressionValue.t = Belt.Map.String.getWithDefault( @@ -52,31 +80,39 @@ let rec fromTypeMap = typeMap => { "properties", default, ) - //TODO: map type modifiers - switch evTypeTag { - | IEvString("typeIdentifier") => ItModifiedType({modifiedType: fromIEvValue(evTypeIdentifier)}) + + let modifiers = + typeMap->Belt.Map.String.keep((k, _v) => ["min", "max", "memberOf"]->Js.Array2.includes(k)) + + let makeIt = switch evTypeTag { + | IEvString("typeIdentifier") => fromIEvValue(evTypeIdentifier) | IEvString("typeOr") => ItTypeOr({typeOr: fromIEvArray(evTypeOr)}) | IEvString("typeFunction") => ItTypeFunction({inputs: fromIEvArray(evInputs), output: fromIEvValue(evOutput)}) | IEvString("typeArray") => ItTypeArray({element: fromIEvValue(evElement)}) | IEvString("typeTuple") => ItTypeTuple({elements: fromIEvArray(evElements)}) | IEvString("typeRecord") => ItTypeRecord({properties: fromIEvRecord(evProperties)}) - | _ => raise(Reducer_Exception.ImpossibleException) + | _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_T-evTypeTag")) } + + Belt.Map.String.isEmpty(modifiers) + ? makeIt + : ItModifiedType({modifiedType: makeIt, modifiers: modifiers}) } -and fromIEvValue = (ievValue: InternalExpressionValue.t) => + +and fromIEvValue = (ievValue: InternalExpressionValue.t): iType => switch ievValue { | IEvTypeIdentifier(typeIdentifier) => ItTypeIdentifier({typeIdentifier}) | IEvType(typeMap) => fromTypeMap(typeMap) - | _ => raise(Reducer_Exception.ImpossibleException) + | _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_T-ievValue")) } and fromIEvArray = (ievArray: InternalExpressionValue.t) => switch ievArray { | IEvArray(array) => array->Belt.Array.map(fromIEvValue) - | _ => raise(Reducer_Exception.ImpossibleException) + | _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_T-ievArray")) } and fromIEvRecord = (ievRecord: InternalExpressionValue.t) => switch ievRecord { | IEvRecord(record) => record->Belt.Map.String.map(fromIEvValue) - | _ => raise(Reducer_Exception.ImpossibleException) + | _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_T-ievRecord")) } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeBuilder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeBuilder.res index e51f901a..d3906a38 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeBuilder.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeBuilder.res @@ -56,7 +56,7 @@ let typeFunction = anArray => { let typeArray = element => { let newRecord = Belt.Map.String.fromArray([ - ("typeTag", IEvString("typeTuple")), + ("typeTag", IEvString("typeArray")), ("element", element), ]) newRecord->IEvType->Ok @@ -64,22 +64,14 @@ let typeArray = element => { let typeTuple = anArray => { let newRecord = Belt.Map.String.fromArray([ - ("typeTag", IEvString("typeArray")), + ("typeTag", IEvString("typeTuple")), ("elements", IEvArray(anArray)), ]) newRecord->IEvType->Ok } -let typeRecord = arrayOfPairs => { - let newProperties = - Belt.Array.map(arrayOfPairs, pairValue => - switch pairValue { - | IEvArray([IEvString(key), valueValue]) => (key, valueValue) - | _ => ("wrong key type", pairValue->toStringWithType->IEvString) - } - ) - ->Belt.Map.String.fromArray - ->IEvRecord +let typeRecord = propertyMap => { + let newProperties = propertyMap->IEvRecord let newRecord = Belt.Map.String.fromArray([ ("typeTag", IEvString("typeRecord")), ("properties", newProperties), diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res index 18cb804a..a1a6bdc2 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res @@ -1,13 +1,10 @@ -module ExpressionT = Reducer_Expression_T +// module ErrorValue = Reducer_ErrorValue module InternalExpressionValue = ReducerInterface_InternalExpressionValue module T = Reducer_Type_T -module TypeBuilder = Reducer_Type_TypeBuilder +// module TypeBuilder = Reducer_Type_TypeBuilder open InternalExpressionValue -type typeErrorValue = - | TypeError(T.iType, InternalExpressionValue.t) - | TypeErrorWithPosition(T.iType, InternalExpressionValue.t, int) - | TypeErrorWithProperty(T.iType, InternalExpressionValue.t, string) +type typeErrorValue = TypeError(T.t, InternalExpressionValue.t) let rec isOfResolvedIType = (anIType: T.iType, aValue): result => { let caseTypeIdentifier = (anUpperTypeName, aValue) => { @@ -24,16 +21,16 @@ let rec isOfResolvedIType = (anIType: T.iType, aValue): result switch Belt.Map.String.get(map, property) { | Some(propertyValue) => isOfResolvedIType(propertyType, propertyValue) - | None => TypeErrorWithProperty(anIType, evValue, property)->Error + | None => TypeError(anIType, evValue)->Error } ) }) } let _caseArray = (anIType, evValue, elementType, anArray) => { - Belt.Array.reduceWithIndex(anArray, Ok(true), (acc, element, index) => { + Belt.Array.reduceWithIndex(anArray, Ok(true), (acc, element, _index) => { switch isOfResolvedIType(elementType, element) { | Ok(_) => acc - | Error(_) => TypeErrorWithPosition(anIType, evValue, index)->Error + | Error(_) => TypeError(anIType, evValue)->Error } }) } @@ -48,12 +45,12 @@ let rec isOfResolvedIType = (anIType: T.iType, aValue): result raise(Reducer_Exception.ImpossibleException) // | ItTypeTuple({elements: anITypeArray}) => raise(Reducer_Exception.ImpossibleException) // | ItTypeRecord({properties: anITypeMap}) => raise(Reducer_Exception.ImpossibleException) - | _ => raise(Reducer_Exception.ImpossibleException) + | _ => raise(Reducer_Exception.ImpossibleException("Reducer_TypeChecker-isOfResolvedIType")) } } -let isOfResolvedType = (aType: InternalExpressionValue.t, aValue): result => - aType->T.fromIEvValue->isOfResolvedIType(aValue) +// let isOfResolvedType = (aType: InternalExpressionValue.t, aValue): result => +// aType->T.fromIEvValue->isOfResolvedIType(aValue) // TODO: Work in progress. Code is commented to make an a release of other features // let checkArguments = ( @@ -70,12 +67,5 @@ let isOfResolvedType = (aType: InternalExpressionValue.t, aValue): result raise(Reducer_Exception.ImpossibleException) // } // let rTupleType = TypeBuilder.typeTuple(inputs) -// Belt.Result.flatMap(rTupleType, tuppleType => isOfResolvedType(tuppleType, args->IEvArray)) +// Belt.Result.flatMap(rTupleType, tupleType => isOfResolvedType(tupleType, args->IEvArray)) // } - -// let compileTypeExpression = (typeExpression: string, bindings: ExpressionT.bindings, reducerFn: ExpressionT.reducerFn) => { -// statement = `type compiled=${typeExpression}` - -// } - -//TODO: asGuard From b65aeaf0d2c59f7f855d67d588ff645e8b108412 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Sat, 16 Jul 2022 17:08:23 +0200 Subject: [PATCH 14/40] spell check --- .../Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res | 4 ++-- .../Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res | 2 +- .../Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res | 4 ++-- .../Reducer/Reducer_Expression/Reducer_Expression_T.res | 4 ++-- .../rescript/Reducer/Reducer_Extra/Reducer_Extra_Array.res | 4 ++-- .../src/rescript/Reducer/Reducer_Extra/Reducer_Extra_List.res | 4 ++-- .../rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res index ea18effc..f1dcd4bc 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res @@ -63,8 +63,8 @@ describe("Peggy parse type", () => { "{(::$_typeOf_$ :weekend (::$_typeOr_$ (::$_constructArray_$ ((::$_typeConstructor_$ #Saturday (::$_constructArray_$ ())) (::$_typeConstructor_$ #Sunday (::$_constructArray_$ ()))))))}", ) }) - describe("type paranthesis", () => { - //$ is introduced to avoid paranthesis + describe("type parenthesis", () => { + //$ is introduced to avoid parenthesis testParse( "answer: (number|string)<-opaque", "{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}", diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res index 18e8121d..d0609d09 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res @@ -3,7 +3,7 @@ open Reducer_Peggy_TestHelpers describe("Peggy to Expression", () => { describe("literals operators parenthesis", () => { - // Note that there is always an outer block. Otherwise, external bindings are ignrored at the first statement + // Note that there is always an outer block. Otherwise, external bindings are ignored at the first statement testToExpression("1", "{1}", ~v="1", ()) testToExpression("'hello'", "{'hello'}", ~v="'hello'", ()) testToExpression("true", "{true}", ~v="true", ()) 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 07766aca..0e8a479e 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 @@ -10,8 +10,8 @@ open ReducerInterface_InternalExpressionValue open Reducer_ErrorValue /* - MathJs provides default implementations for builtins - This is where all the expected builtins like + = * / sin cos log ln etc are handled + MathJs provides default implementations for built-ins + This is where all the expected built-ins like + = * / sin cos log ln etc are handled DO NOT try to add external function mapping here! */ 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 bf4d0170..c9739be3 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 @@ -30,12 +30,12 @@ let rec toString = expression => switch expression { | EList(list{EValue(IEvCall("$$_block_$$")), ...statements}) => `{${Belt.List.map(statements, aValue => toString(aValue)) - ->Extra.List.interperse("; ") + ->Extra.List.intersperse("; ") ->Belt.List.toArray ->Js.String.concatMany("")}}` | EList(aList) => `(${Belt.List.map(aList, aValue => toString(aValue)) - ->Extra.List.interperse(" ") + ->Extra.List.intersperse(" ") ->Belt.List.toArray ->Js.String.concatMany("")})` | EValue(aValue) => InternalExpressionValue.toString(aValue) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Extra/Reducer_Extra_Array.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Extra/Reducer_Extra_Array.res index 58dd4ffd..8c9f2fbb 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Extra/Reducer_Extra_Array.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Extra/Reducer_Extra_Array.res @@ -3,5 +3,5 @@ */ module ExtraList = Reducer_Extra_List -let interperse = (anArray, seperator) => - anArray->Belt.List.fromArray->ExtraList.interperse(seperator)->Belt.List.toArray +let intersperse = (anArray, seperator) => + anArray->Belt.List.fromArray->ExtraList.intersperse(seperator)->Belt.List.toArray diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Extra/Reducer_Extra_List.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Extra/Reducer_Extra_List.res index 9b3bcc3d..b723cca4 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Extra/Reducer_Extra_List.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Extra/Reducer_Extra_List.res @@ -1,9 +1,9 @@ /* Insert seperator between the elements of a list */ -let rec interperse = (aList, seperator) => +let rec intersperse = (aList, seperator) => switch aList { | list{} => list{} | list{a} => list{a} - | list{a, ...rest} => list{a, seperator, ...interperse(rest, seperator)} + | list{a, ...rest} => list{a, seperator, ...intersperse(rest, seperator)} } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res index 67873c61..a38c66e9 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res @@ -91,7 +91,7 @@ let rec pgToString = (peggyNode: peggyNode): string => { args->Js.Array2.map(arg => PgNodeIdentifier(arg)->pgToString)->Js.Array2.toString let nodesToStringUsingSeparator = (nodes: array, separator: string): string => - nodes->Js.Array2.map(toString)->Extra.Array.interperse(separator)->Js.String.concatMany("") + nodes->Js.Array2.map(toString)->Extra.Array.intersperse(separator)->Js.String.concatMany("") switch peggyNode { | PgNodeBlock(node) => "{" ++ node["statements"]->nodesToStringUsingSeparator("; ") ++ "}" From 0c032e710c9a12a0a170e48772630bda3bc5b4b9 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 16 Jul 2022 14:01:00 -0700 Subject: [PATCH 15/40] Moved function library modules to separate files --- .../FunctionRegistry_Library.res | 915 +----------------- .../FunctionRegistry/Library/FR_Dict.res | 169 ++++ .../FunctionRegistry/Library/FR_Dist.res | 155 +++ .../FunctionRegistry/Library/FR_Fn.res | 61 ++ .../FunctionRegistry/Library/FR_List.res | 128 +++ .../FunctionRegistry/Library/FR_Number.res | 233 +++++ .../FunctionRegistry/Library/FR_Pointset.res | 55 ++ .../FunctionRegistry/Library/FR_Scoring.res | 90 ++ 8 files changed, 898 insertions(+), 908 deletions(-) create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 5d68c7b9..949837b5 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -1,910 +1,9 @@ -open FunctionRegistry_Core -open FunctionRegistry_Helpers - -let twoArgs = E.Tuple2.toFnCall - -module Declaration = { - let frType = FRTypeRecord([ - ("fn", FRTypeLambda), - ("inputs", FRTypeArray(FRTypeRecord([("min", FRTypeNumber), ("max", FRTypeNumber)]))), - ]) - - let fromExpressionValue = (e: frValue): result => { - switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs([e]) { - | Ok([FRValueLambda(lambda), FRValueArray(inputs)]) => { - open FunctionRegistry_Helpers.Prepare - let getMinMax = arg => - ToValueArray.Record.toArgs([arg]) - ->E.R.bind(ToValueTuple.twoNumbers) - ->E.R2.fmap(((min, max)) => Declaration.ContinuousFloatArg.make(min, max)) - inputs - ->E.A2.fmap(getMinMax) - ->E.A.R.firstErrorOrOpen - ->E.R2.fmap(args => ReducerInterface_InternalExpressionValue.IEvDeclaration( - Declaration.make(lambda, args), - )) - } - | Error(r) => Error(r) - | Ok(_) => Error(FunctionRegistry_Helpers.impossibleError) - } - } -} - -module PointSet = { - let nameSpace = "PointSet" - let requiresNamespace = true - - let inputsTodist = (inputs: array, makeDist) => { - let array = inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.openA) - let xyCoords = - array->E.R.bind(xyCoords => - xyCoords - ->E.A2.fmap(xyCoord => - [xyCoord]->Prepare.ToValueArray.Record.twoArgs->E.R.bind(Prepare.ToValueTuple.twoNumbers) - ) - ->E.A.R.firstErrorOrOpen - ) - let expressionValue = - xyCoords - ->E.R.bind(r => r->XYShape.T.makeFromZipped->E.R2.errMap(XYShape.Error.toString)) - ->E.R2.fmap(r => ReducerInterface_InternalExpressionValue.IEvDistribution( - PointSet(makeDist(r)), - )) - expressionValue - } - - let library = [ - Function.make( - ~name="makeContinuous", - ~nameSpace, - ~definitions=[ - FnDefinition.make( - ~requiresNamespace, - ~name="makeContinuous", - ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(_, inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), - (), - ), - ], - (), - ), - Function.make( - ~name="makeDiscrete", - ~nameSpace, - ~definitions=[ - FnDefinition.make( - ~requiresNamespace, - ~name="makeDiscrete", - ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], - ~run=(_, inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), - (), - ), - ], - (), - ), - ] -} - -module Functionn = { - let nameSpace = "Function" - let library = [ - Function.make( - ~name="declare", - ~nameSpace, - ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", - ~examples=[ - `declareFn({ - fn: {|a,b| a }, - inputs: [ - {min: 0, max: 100}, - {min: 30, max: 50} - ] -})`, - ], - ~isExperimental=true, - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="declare", - ~inputs=[Declaration.frType], - ~run=(_, inputs, _) => { - inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue) - }, - (), - ), - ], - (), - ), - ] -} - -module DistributionCreation = { - let nameSpace = "Dist" - let output = ReducerInterface_InternalExpressionValue.EvtDistribution - - let fnMake = (~name, ~examples, ~definitions) => { - Function.make(~name, ~nameSpace, ~output, ~examples, ~definitions, ()) - } - - module TwoArgDist = { - let process = (~fn, ~env, r) => - r - ->E.R.bind(Process.DistOrNumberToDist.twoValuesUsingSymbolicDist(~fn, ~values=_, ~env)) - ->E.R2.fmap(Wrappers.evDistribution) - - let make = (name, fn) => { - FnDefinition.make( - ~requiresNamespace=false, - ~name, - ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], - ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), - (), - ) - } - - let makeRecordP5P95 = (name, fn) => { - FnDefinition.make( - ~requiresNamespace=false, - ~name, - ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], - ~run=(_, inputs, env) => - inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), - (), - ) - } - - let makeRecordMeanStdev = (name, fn) => { - FnDefinition.make( - ~name, - ~requiresNamespace=false, - ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], - ~run=(_, inputs, env) => - inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), - (), - ) - } - } - - module OneArgDist = { - let process = (~fn, ~env, r) => - r - ->E.R.bind(Process.DistOrNumberToDist.oneValueUsingSymbolicDist(~fn, ~value=_, ~env)) - ->E.R2.fmap(Wrappers.evDistribution) - - let make = (name, fn) => - FnDefinition.make( - ~requiresNamespace=false, - ~name, - ~inputs=[FRTypeDistOrNumber], - ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), - (), - ) - } - - let library = [ - fnMake( - ~name="normal", - ~examples=["normal(5,1)", "normal({p5: 4, p95: 10})", "normal({mean: 5, stdev: 2})"], - ~definitions=[ - TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), - TwoArgDist.makeRecordP5P95("normal", r => - twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok - ), - TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), - ], - ), - fnMake( - ~name="lognormal", - ~examples=[ - "lognormal(0.5, 0.8)", - "lognormal({p5: 4, p95: 10})", - "lognormal({mean: 5, stdev: 2})", - ], - ~definitions=[ - TwoArgDist.make("lognormal", twoArgs(SymbolicDist.Lognormal.make)), - TwoArgDist.makeRecordP5P95("lognormal", r => - twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok - ), - TwoArgDist.makeRecordMeanStdev( - "lognormal", - twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev), - ), - ], - ), - fnMake( - ~name="uniform", - ~examples=[`uniform(10, 12)`], - ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], - ), - fnMake( - ~name="beta", - ~examples=[`beta(20, 25)`, `beta({mean: 0.39, stdev: 0.1})`], - ~definitions=[ - TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make)), - TwoArgDist.makeRecordMeanStdev("beta", twoArgs(SymbolicDist.Beta.fromMeanAndStdev)), - ], - ), - fnMake( - ~name="cauchy", - ~examples=[`cauchy(5, 1)`], - ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], - ), - fnMake( - ~name="gamma", - ~examples=[`gamma(5, 1)`], - ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], - ), - fnMake( - ~name="logistic", - ~examples=[`logistic(5, 1)`], - ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], - ), - fnMake( - ~name="to (distribution)", - ~examples=[`5 to 10`, `to(5,10)`, `-5 to 5`], - ~definitions=[ - TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), - TwoArgDist.make( - "credibleIntervalToDistribution", - twoArgs(SymbolicDist.From90thPercentile.make), - ), - ], - ), - fnMake( - ~name="exponential", - ~examples=[`exponential(2)`], - ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], - ), - fnMake( - ~name="bernoulli", - ~examples=[`bernoulli(0.5)`], - ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], - ), - fnMake( - ~name="pointMass", - ~examples=[`pointMass(0.5)`], - ~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)], - ), - ] -} - -module Number = { - let nameSpace = "Number" - let requiresNamespace = false - - module NumberToNumber = { - let make = (name, fn) => - FnDefinition.make( - ~requiresNamespace, - ~name, - ~inputs=[FRTypeNumber], - ~run=(_, inputs, _) => { - inputs - ->getOrError(0) - ->E.R.bind(Prepare.oneNumber) - ->E.R2.fmap(fn) - ->E.R2.fmap(Wrappers.evNumber) - }, - (), - ) - } - - module ArrayNumberDist = { - let make = (name, fn) => { - FnDefinition.make( - ~requiresNamespace=false, - ~name, - ~inputs=[FRTypeArray(FRTypeNumber)], - ~run=(_, inputs, _) => - Prepare.ToTypedArray.numbers(inputs) - ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) - ->E.R.bind(fn), - (), - ) - } - let make2 = (name, fn) => { - FnDefinition.make( - ~name, - ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(_, inputs, _) => - Prepare.ToTypedArray.numbers(inputs) - ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) - ->E.R.bind(fn), - (), - ) - } - } - - let library = [ - Function.make( - ~name="floor", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`floor(3.5)`], - ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], - (), - ), - Function.make( - ~name="ceiling", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`ceiling(3.5)`], - ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], - (), - ), - Function.make( - ~name="absolute value", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`abs(3.5)`], - ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], - (), - ), - Function.make( - ~name="exponent", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`exp(3.5)`], - ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], - (), - ), - Function.make( - ~name="log", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`log(3.5)`], - ~definitions=[NumberToNumber.make("log", Js.Math.log)], - (), - ), - Function.make( - ~name="log base 10", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`log10(3.5)`], - ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], - (), - ), - Function.make( - ~name="log base 2", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`log2(3.5)`], - ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], - (), - ), - Function.make( - ~name="round", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`round(3.5)`], - ~definitions=[NumberToNumber.make("round", Js.Math.round)], - (), - ), - Function.make( - ~name="sum", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`sum([3,5,2])`], - ~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="product", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`product([3,5,2])`], - ~definitions=[ - ArrayNumberDist.make("product", r => r->E.A.Floats.product->Wrappers.evNumber->Ok), - ], - (), - ), - Function.make( - ~name="min", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`min([3,5,2])`], - ~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="max", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`max([3,5,2])`], - ~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="mean", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`mean([3,5,2])`], - ~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="geometric mean", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`geomean([3,5,2])`], - ~definitions=[ - ArrayNumberDist.make("geomean", r => r->E.A.Floats.geomean->Wrappers.evNumber->Ok), - ], - (), - ), - Function.make( - ~name="standard deviation", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`stdev([3,5,2,3,5])`], - ~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)], - (), - ), - Function.make( - ~name="variance", - ~nameSpace, - ~output=EvtNumber, - ~examples=[`variance([3,5,2,3,5])`], - ~definitions=[ - ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok), - ], - (), - ), - Function.make( - ~name="sort", - ~nameSpace, - ~output=EvtArray, - ~examples=[`sort([3,5,2,3,5])`], - ~definitions=[ - ArrayNumberDist.make("sort", r => - r->E.A.Floats.sort->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="cumulative sum", - ~nameSpace, - ~output=EvtArray, - ~examples=[`cumsum([3,5,2,3,5])`], - ~definitions=[ - ArrayNumberDist.make("cumsum", r => - r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="cumulative prod", - ~nameSpace, - ~output=EvtArray, - ~examples=[`cumprod([3,5,2,3,5])`], - ~definitions=[ - ArrayNumberDist.make("cumprod", r => - r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - Function.make( - ~name="diff", - ~nameSpace, - ~output=EvtArray, - ~examples=[`diff([3,5,2,3,5])`], - ~definitions=[ - ArrayNumberDist.make("diff", r => - r->E.A.Floats.diff->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok - ), - ], - (), - ), - ] -} - -module Dict = { - let nameSpace = "Dict" - module Internals = { - type t = ReducerInterface_InternalExpressionValue.map - - let keys = (a: t): internalExpressionValue => IEvArray( - Belt.Map.String.keysToArray(a)->E.A2.fmap(Wrappers.evString), - ) - - let values = (a: t): internalExpressionValue => IEvArray(Belt.Map.String.valuesToArray(a)) - - let toList = (a: t): internalExpressionValue => - Belt.Map.String.toArray(a) - ->E.A2.fmap(((key, value)) => Wrappers.evArray([IEvString(key), value])) - ->Wrappers.evArray - - let fromList = (items: array): result< - internalExpressionValue, - string, - > => - items - ->E.A2.fmap(item => { - switch (item: internalExpressionValue) { - | IEvArray([IEvString(string), value]) => (string, value)->Ok - | _ => Error(impossibleError) - } - }) - ->E.A.R.firstErrorOrOpen - ->E.R2.fmap(Belt.Map.String.fromArray) - ->E.R2.fmap(Wrappers.evRecord) - - let merge = (a: t, b: t): internalExpressionValue => IEvRecord( - Belt.Map.String.merge(a, b, (_, _, c) => c), - ) - - //Belt.Map.String has a function for mergeMany, but I couldn't understand how to use it yet. - let mergeMany = (a: array): internalExpressionValue => { - let mergedValues = - a->E.A2.fmap(Belt.Map.String.toArray)->Belt.Array.concatMany->Belt.Map.String.fromArray - IEvRecord(mergedValues) - } - } - - let library = [ - Function.make( - ~name="merge", - ~nameSpace, - ~output=EvtRecord, - ~examples=[`Dict.merge({a: 1, b: 2}, {c: 3, d: 4})`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="merge", - ~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)], - ~run=(inputs, _, _) => { - switch inputs { - | [IEvRecord(d1), IEvRecord(d2)] => Internals.merge(d1, d2)->Ok - | _ => Error(impossibleError) - } - }, - (), - ), - ], - (), - ), - //TODO: Change to use new mergeMany() function. - Function.make( - ~name="mergeMany", - ~nameSpace, - ~output=EvtRecord, - ~examples=[`Dict.mergeMany([{a: 1, b: 2}, {c: 3, d: 4}])`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="mergeMany", - ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], - ~run=(_, inputs, _) => - inputs - ->Prepare.ToTypedArray.dicts - ->E.R2.fmap(E.Dict.concatMany) - ->E.R2.fmap(Js.Dict.map((. r) => FunctionRegistry_Core.FRType.matchReverse(r))) - ->E.R2.fmap(r => r->Js.Dict.entries->Belt.Map.String.fromArray) - ->E.R2.fmap(Wrappers.evRecord), - (), - ), - ], - (), - ), - Function.make( - ~name="keys", - ~nameSpace, - ~output=EvtArray, - ~examples=[`Dict.keys({a: 1, b: 2})`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="keys", - ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvRecord(d1)] => Internals.keys(d1)->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="values", - ~nameSpace, - ~output=EvtArray, - ~examples=[`Dict.values({a: 1, b: 2})`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="values", - ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvRecord(d1)] => Internals.values(d1)->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="toList", - ~nameSpace, - ~output=EvtArray, - ~examples=[`Dict.toList({a: 1, b: 2})`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="toList", - ~inputs=[FRTypeDict(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvRecord(dict)] => dict->Internals.toList->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="fromList", - ~nameSpace, - ~output=EvtRecord, - ~examples=[`Dict.fromList({a: 1, b: 2})`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=true, - ~name="fromList", - ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], - ~run=(inputs, _, _) => - switch inputs { - | [IEvArray(items)] => Internals.fromList(items) - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - ] -} - -module List = { - let nameSpace = "List" - let requiresNamespace = true - - module Internals = { - let makeFromNumber = ( - n: float, - value: internalExpressionValue, - ): internalExpressionValue => IEvArray(Belt.Array.make(E.Float.toInt(n), value)) - - let upTo = (low: float, high: float): internalExpressionValue => IEvArray( - E.A.Floats.range(low, high, (high -. low +. 1.0)->E.Float.toInt)->E.A2.fmap( - Wrappers.evNumber, - ), - ) - - let first = (v: array): result => - v->E.A.first |> E.O.toResult("No first element") - - let last = (v: array): result => - v->E.A.last |> E.O.toResult("No last element") - - let reverse = (array: array): internalExpressionValue => IEvArray( - Belt.Array.reverse(array), - ) - } - - let library = [ - Function.make( - ~name="make", - ~nameSpace, - ~output=EvtArray, - ~examples=[`List.make(2, "testValue")`], - ~definitions=[ - //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. - FnDefinition.make( - ~requiresNamespace, - ~name="make", - ~inputs=[FRTypeNumber, FRTypeAny], - ~run=(inputs, _, _) => { - switch inputs { - | [IEvNumber(number), value] => Internals.makeFromNumber(number, value)->Ok - | _ => Error(impossibleError) - } - }, - (), - ), - ], - (), - ), - Function.make( - ~name="upTo", - ~nameSpace, - ~output=EvtArray, - ~examples=[`List.upTo(1,4)`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace, - ~name="upTo", - ~inputs=[FRTypeNumber, FRTypeNumber], - ~run=(_, inputs, _) => - inputs - ->Prepare.ToValueTuple.twoNumbers - ->E.R2.fmap(((low, high)) => Internals.upTo(low, high)), - (), - ), - ], - (), - ), - Function.make( - ~name="first", - ~nameSpace, - ~examples=[`List.first([1,4,5])`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace, - ~name="first", - ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvArray(array)] => Internals.first(array) - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="last", - ~nameSpace, - ~examples=[`List.last([1,4,5])`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=false, - ~name="last", - ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvArray(array)] => Internals.last(array) - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - Function.make( - ~name="reverse", - ~nameSpace, - ~output=EvtArray, - ~examples=[`List.reverse([1,4,5])`], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace=false, - ~name="reverse", - ~inputs=[FRTypeArray(FRTypeAny)], - ~run=(inputs, _, _) => - switch inputs { - | [IEvArray(array)] => Internals.reverse(array)->Ok - | _ => Error(impossibleError) - }, - (), - ), - ], - (), - ), - ] -} - -module Scoring = { - let nameSpace = "Dist" - let requiresNamespace = false - - let runScoring = (estimate, answer, prior, env) => { - GenericDist.Score.logScore(~estimate, ~answer, ~prior, ~env) - ->E.R2.fmap(FunctionRegistry_Helpers.Wrappers.evNumber) - ->E.R2.errMap(DistributionTypes.Error.toString) - } - - let library = [ - Function.make( - ~name="logScore", - ~nameSpace, - ~output=EvtNumber, - ~examples=[ - "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}, prior: normal(5.5,3)})", - "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}})", - "Dist.logScore({estimate: normal(5,2), answer: 4.5})", - ], - ~definitions=[ - FnDefinition.make( - ~requiresNamespace, - ~name="logScore", - ~inputs=[ - FRTypeRecord([ - ("estimate", FRTypeDist), - ("answer", FRTypeDistOrNumber), - ("prior", FRTypeDist), - ]), - ], - ~run=(_, inputs, env) => { - switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) { - | Ok([ - FRValueDist(estimate), - FRValueDistOrNumber(FRValueDist(d)), - FRValueDist(prior), - ]) => - runScoring(estimate, Score_Dist(d), Some(prior), env) - | Ok([ - FRValueDist(estimate), - FRValueDistOrNumber(FRValueNumber(d)), - FRValueDist(prior), - ]) => - runScoring(estimate, Score_Scalar(d), Some(prior), env) - | Error(e) => Error(e) - | _ => Error(FunctionRegistry_Helpers.impossibleError) - } - }, - (), - ), - FnDefinition.make( - ~name="logScore", - ~requiresNamespace, - ~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])], - ~run=(_, inputs, env) => { - switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) { - | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) => - runScoring(estimate, Score_Dist(d), None, env) - | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueNumber(d))]) => - runScoring(estimate, Score_Scalar(d), None, env) - | Error(e) => Error(e) - | _ => Error(FunctionRegistry_Helpers.impossibleError) - } - }, - (), - ), - ], - (), - ), - Function.make( - ~name="klDivergence", - ~nameSpace, - ~output=EvtNumber, - ~examples=[ - "Dist.klDivergence(normal(5,2), normal(5,1.5)", - ], - ~definitions=[ - FnDefinition.make( - ~name="klDivergence", - ~requiresNamespace, - ~inputs=[FRTypeDist, FRTypeDist], - ~run=(_, inputs, env) => { - switch inputs { - | [FRValueDist(estimate), FRValueDist(d)] => - runScoring(estimate, Score_Dist(d), None, env) - | _ => Error(FunctionRegistry_Helpers.impossibleError) - } - }, - (), - ), - ], - (), - ), - ] -} - let registry = Belt.Array.concatMany([ - PointSet.library, - Functionn.library, - Number.library, - Dict.library, - List.library, - DistributionCreation.library, - Scoring.library, + FR_Dict.library, + FR_Dist.library, + FR_Fn.library, + FR_List.library, + FR_Number.library, + FR_Pointset.library, + FR_Scoring.library ]) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res new file mode 100644 index 00000000..c8d28a78 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res @@ -0,0 +1,169 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +let nameSpace = "Dict" + +module Internals = { + type t = ReducerInterface_InternalExpressionValue.map + + let keys = (a: t): internalExpressionValue => IEvArray( + Belt.Map.String.keysToArray(a)->E.A2.fmap(Wrappers.evString), + ) + + let values = (a: t): internalExpressionValue => IEvArray(Belt.Map.String.valuesToArray(a)) + + let toList = (a: t): internalExpressionValue => + Belt.Map.String.toArray(a) + ->E.A2.fmap(((key, value)) => Wrappers.evArray([IEvString(key), value])) + ->Wrappers.evArray + + let fromList = (items: array): result => + items + ->E.A2.fmap(item => { + switch (item: internalExpressionValue) { + | IEvArray([IEvString(string), value]) => (string, value)->Ok + | _ => Error(impossibleError) + } + }) + ->E.A.R.firstErrorOrOpen + ->E.R2.fmap(Belt.Map.String.fromArray) + ->E.R2.fmap(Wrappers.evRecord) + + let merge = (a: t, b: t): internalExpressionValue => IEvRecord( + Belt.Map.String.merge(a, b, (_, _, c) => c), + ) + + //Belt.Map.String has a function for mergeMany, but I couldn't understand how to use it yet. + let mergeMany = (a: array): internalExpressionValue => { + let mergedValues = + a->E.A2.fmap(Belt.Map.String.toArray)->Belt.Array.concatMany->Belt.Map.String.fromArray + IEvRecord(mergedValues) + } +} + +let library = [ + Function.make( + ~name="merge", + ~nameSpace, + ~output=EvtRecord, + ~examples=[`Dict.merge({a: 1, b: 2}, {c: 3, d: 4})`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="merge", + ~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)], + ~run=(inputs, _, _) => { + switch inputs { + | [IEvRecord(d1), IEvRecord(d2)] => Internals.merge(d1, d2)->Ok + | _ => Error(impossibleError) + } + }, + (), + ), + ], + (), + ), + //TODO: Change to use new mergeMany() function. + Function.make( + ~name="mergeMany", + ~nameSpace, + ~output=EvtRecord, + ~examples=[`Dict.mergeMany([{a: 1, b: 2}, {c: 3, d: 4}])`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="mergeMany", + ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], + ~run=(_, inputs, _) => + inputs + ->Prepare.ToTypedArray.dicts + ->E.R2.fmap(E.Dict.concatMany) + ->E.R2.fmap(Js.Dict.map((. r) => FunctionRegistry_Core.FRType.matchReverse(r))) + ->E.R2.fmap(r => r->Js.Dict.entries->Belt.Map.String.fromArray) + ->E.R2.fmap(Wrappers.evRecord), + (), + ), + ], + (), + ), + Function.make( + ~name="keys", + ~nameSpace, + ~output=EvtArray, + ~examples=[`Dict.keys({a: 1, b: 2})`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="keys", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvRecord(d1)] => Internals.keys(d1)->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="values", + ~nameSpace, + ~output=EvtArray, + ~examples=[`Dict.values({a: 1, b: 2})`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="values", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvRecord(d1)] => Internals.values(d1)->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="toList", + ~nameSpace, + ~output=EvtArray, + ~examples=[`Dict.toList({a: 1, b: 2})`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="toList", + ~inputs=[FRTypeDict(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvRecord(dict)] => dict->Internals.toList->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="fromList", + ~nameSpace, + ~output=EvtRecord, + ~examples=[`Dict.fromList({a: 1, b: 2})`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="fromList", + ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], + ~run=(inputs, _, _) => + switch inputs { + | [IEvArray(items)] => Internals.fromList(items) + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), +] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res new file mode 100644 index 00000000..35e17dd3 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res @@ -0,0 +1,155 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers +let twoArgs = E.Tuple2.toFnCall + +module DistributionCreation = { + let nameSpace = "Dist" + let output = ReducerInterface_InternalExpressionValue.EvtDistribution + + let fnMake = (~name, ~examples, ~definitions) => { + Function.make(~name, ~nameSpace, ~output, ~examples, ~definitions, ()) + } + + module TwoArgDist = { + let process = (~fn, ~env, r) => + r + ->E.R.bind(Process.DistOrNumberToDist.twoValuesUsingSymbolicDist(~fn, ~values=_, ~env)) + ->E.R2.fmap(Wrappers.evDistribution) + + let make = (name, fn) => { + FnDefinition.make( + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], + ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), + (), + ) + } + + let makeRecordP5P95 = (name, fn) => { + FnDefinition.make( + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], + ~run=(_, inputs, env) => + inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), + (), + ) + } + + let makeRecordMeanStdev = (name, fn) => { + FnDefinition.make( + ~name, + ~requiresNamespace=false, + ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], + ~run=(_, inputs, env) => + inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), + (), + ) + } + } + + module OneArgDist = { + let process = (~fn, ~env, r) => + r + ->E.R.bind(Process.DistOrNumberToDist.oneValueUsingSymbolicDist(~fn, ~value=_, ~env)) + ->E.R2.fmap(Wrappers.evDistribution) + + let make = (name, fn) => + FnDefinition.make( + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeDistOrNumber], + ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), + (), + ) + } + + let library = [ + fnMake( + ~name="normal", + ~examples=["normal(5,1)", "normal({p5: 4, p95: 10})", "normal({mean: 5, stdev: 2})"], + ~definitions=[ + TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), + TwoArgDist.makeRecordP5P95("normal", r => + twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok + ), + TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), + ], + ), + fnMake( + ~name="lognormal", + ~examples=[ + "lognormal(0.5, 0.8)", + "lognormal({p5: 4, p95: 10})", + "lognormal({mean: 5, stdev: 2})", + ], + ~definitions=[ + TwoArgDist.make("lognormal", twoArgs(SymbolicDist.Lognormal.make)), + TwoArgDist.makeRecordP5P95("lognormal", r => + twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok + ), + TwoArgDist.makeRecordMeanStdev( + "lognormal", + twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev), + ), + ], + ), + fnMake( + ~name="uniform", + ~examples=[`uniform(10, 12)`], + ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], + ), + fnMake( + ~name="beta", + ~examples=[`beta(20, 25)`, `beta({mean: 0.39, stdev: 0.1})`], + ~definitions=[ + TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make)), + TwoArgDist.makeRecordMeanStdev("beta", twoArgs(SymbolicDist.Beta.fromMeanAndStdev)), + ], + ), + fnMake( + ~name="cauchy", + ~examples=[`cauchy(5, 1)`], + ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], + ), + fnMake( + ~name="gamma", + ~examples=[`gamma(5, 1)`], + ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], + ), + fnMake( + ~name="logistic", + ~examples=[`logistic(5, 1)`], + ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], + ), + fnMake( + ~name="to (distribution)", + ~examples=[`5 to 10`, `to(5,10)`, `-5 to 5`], + ~definitions=[ + TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), + TwoArgDist.make( + "credibleIntervalToDistribution", + twoArgs(SymbolicDist.From90thPercentile.make), + ), + ], + ), + fnMake( + ~name="exponential", + ~examples=[`exponential(2)`], + ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], + ), + fnMake( + ~name="bernoulli", + ~examples=[`bernoulli(0.5)`], + ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], + ), + fnMake( + ~name="pointMass", + ~examples=[`pointMass(0.5)`], + ~definitions=[OneArgDist.make("pointMass", SymbolicDist.Float.makeSafe)], + ), + ] +} + +let library = DistributionCreation.library \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res new file mode 100644 index 00000000..b30cac2d --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res @@ -0,0 +1,61 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +module Declaration = { + let frType = FRTypeRecord([ + ("fn", FRTypeLambda), + ("inputs", FRTypeArray(FRTypeRecord([("min", FRTypeNumber), ("max", FRTypeNumber)]))), + ]) + + let fromExpressionValue = (e: frValue): result => { + switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs([e]) { + | Ok([FRValueLambda(lambda), FRValueArray(inputs)]) => { + open FunctionRegistry_Helpers.Prepare + let getMinMax = arg => + ToValueArray.Record.toArgs([arg]) + ->E.R.bind(ToValueTuple.twoNumbers) + ->E.R2.fmap(((min, max)) => Declaration.ContinuousFloatArg.make(min, max)) + inputs + ->E.A2.fmap(getMinMax) + ->E.A.R.firstErrorOrOpen + ->E.R2.fmap(args => ReducerInterface_InternalExpressionValue.IEvDeclaration( + Declaration.make(lambda, args), + )) + } + | Error(r) => Error(r) + | Ok(_) => Error(FunctionRegistry_Helpers.impossibleError) + } + } +} + +let nameSpace = "Function" + +let library = [ + Function.make( + ~name="declare", + ~nameSpace, + ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", + ~examples=[ + `declareFn({ + fn: {|a,b| a }, + inputs: [ + {min: 0, max: 100}, + {min: 30, max: 50} + ] +})`, + ], + ~isExperimental=true, + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=true, + ~name="declare", + ~inputs=[Declaration.frType], + ~run=(_, inputs, _) => { + inputs->getOrError(0)->E.R.bind(Declaration.fromExpressionValue) + }, + (), + ), + ], + (), + ), +] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res new file mode 100644 index 00000000..9c064966 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res @@ -0,0 +1,128 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +let nameSpace = "List" +let requiresNamespace = true + +module Internals = { + let makeFromNumber = ( + n: float, + value: internalExpressionValue, + ): internalExpressionValue => IEvArray(Belt.Array.make(E.Float.toInt(n), value)) + + let upTo = (low: float, high: float): internalExpressionValue => IEvArray( + E.A.Floats.range(low, high, (high -. low +. 1.0)->E.Float.toInt)->E.A2.fmap(Wrappers.evNumber), + ) + + let first = (v: array): result => + v->E.A.first |> E.O.toResult("No first element") + + let last = (v: array): result => + v->E.A.last |> E.O.toResult("No last element") + + let reverse = (array: array): internalExpressionValue => IEvArray( + Belt.Array.reverse(array), + ) +} + +let library = [ + Function.make( + ~name="make", + ~nameSpace, + ~output=EvtArray, + ~examples=[`List.make(2, "testValue")`], + ~definitions=[ + //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. + FnDefinition.make( + ~requiresNamespace, + ~name="make", + ~inputs=[FRTypeNumber, FRTypeAny], + ~run=(inputs, _, _) => { + switch inputs { + | [IEvNumber(number), value] => Internals.makeFromNumber(number, value)->Ok + | _ => Error(impossibleError) + } + }, + (), + ), + ], + (), + ), + Function.make( + ~name="upTo", + ~nameSpace, + ~output=EvtArray, + ~examples=[`List.upTo(1,4)`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace, + ~name="upTo", + ~inputs=[FRTypeNumber, FRTypeNumber], + ~run=(_, inputs, _) => + inputs + ->Prepare.ToValueTuple.twoNumbers + ->E.R2.fmap(((low, high)) => Internals.upTo(low, high)), + (), + ), + ], + (), + ), + Function.make( + ~name="first", + ~nameSpace, + ~examples=[`List.first([1,4,5])`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace, + ~name="first", + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvArray(array)] => Internals.first(array) + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="last", + ~nameSpace, + ~examples=[`List.last([1,4,5])`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=false, + ~name="last", + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvArray(array)] => Internals.last(array) + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), + Function.make( + ~name="reverse", + ~nameSpace, + ~output=EvtArray, + ~examples=[`List.reverse([1,4,5])`], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace=false, + ~name="reverse", + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(inputs, _, _) => + switch inputs { + | [IEvArray(array)] => Internals.reverse(array)->Ok + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), +] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res new file mode 100644 index 00000000..0dba4c9a --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res @@ -0,0 +1,233 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +let nameSpace = "Number" +let requiresNamespace = false + +module NumberToNumber = { + let make = (name, fn) => + FnDefinition.make( + ~requiresNamespace, + ~name, + ~inputs=[FRTypeNumber], + ~run=(_, inputs, _) => { + inputs + ->getOrError(0) + ->E.R.bind(Prepare.oneNumber) + ->E.R2.fmap(fn) + ->E.R2.fmap(Wrappers.evNumber) + }, + (), + ) +} + +module ArrayNumberDist = { + let make = (name, fn) => { + FnDefinition.make( + ~requiresNamespace=false, + ~name, + ~inputs=[FRTypeArray(FRTypeNumber)], + ~run=(_, inputs, _) => + Prepare.ToTypedArray.numbers(inputs) + ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) + ->E.R.bind(fn), + (), + ) + } + let make2 = (name, fn) => { + FnDefinition.make( + ~name, + ~inputs=[FRTypeArray(FRTypeAny)], + ~run=(_, inputs, _) => + Prepare.ToTypedArray.numbers(inputs) + ->E.R.bind(r => E.A.length(r) === 0 ? Error("List is empty") : Ok(r)) + ->E.R.bind(fn), + (), + ) + } +} + +let library = [ + Function.make( + ~name="floor", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`floor(3.5)`], + ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], + (), + ), + Function.make( + ~name="ceiling", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`ceiling(3.5)`], + ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], + (), + ), + Function.make( + ~name="absolute value", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`abs(3.5)`], + ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], + (), + ), + Function.make( + ~name="exponent", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`exp(3.5)`], + ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], + (), + ), + Function.make( + ~name="log", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`log(3.5)`], + ~definitions=[NumberToNumber.make("log", Js.Math.log)], + (), + ), + Function.make( + ~name="log base 10", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`log10(3.5)`], + ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], + (), + ), + Function.make( + ~name="log base 2", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`log2(3.5)`], + ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], + (), + ), + Function.make( + ~name="round", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`round(3.5)`], + ~definitions=[NumberToNumber.make("round", Js.Math.round)], + (), + ), + Function.make( + ~name="sum", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`sum([3,5,2])`], + ~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="product", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`product([3,5,2])`], + ~definitions=[ + ArrayNumberDist.make("product", r => r->E.A.Floats.product->Wrappers.evNumber->Ok), + ], + (), + ), + Function.make( + ~name="min", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`min([3,5,2])`], + ~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="max", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`max([3,5,2])`], + ~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="mean", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`mean([3,5,2])`], + ~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="geometric mean", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`geomean([3,5,2])`], + ~definitions=[ + ArrayNumberDist.make("geomean", r => r->E.A.Floats.geomean->Wrappers.evNumber->Ok), + ], + (), + ), + Function.make( + ~name="standard deviation", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`stdev([3,5,2,3,5])`], + ~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)], + (), + ), + Function.make( + ~name="variance", + ~nameSpace, + ~output=EvtNumber, + ~examples=[`variance([3,5,2,3,5])`], + ~definitions=[ + ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok), + ], + (), + ), + Function.make( + ~name="sort", + ~nameSpace, + ~output=EvtArray, + ~examples=[`sort([3,5,2,3,5])`], + ~definitions=[ + ArrayNumberDist.make("sort", r => + r->E.A.Floats.sort->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), + Function.make( + ~name="cumulative sum", + ~nameSpace, + ~output=EvtArray, + ~examples=[`cumsum([3,5,2,3,5])`], + ~definitions=[ + ArrayNumberDist.make("cumsum", r => + r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), + Function.make( + ~name="cumulative prod", + ~nameSpace, + ~output=EvtArray, + ~examples=[`cumprod([3,5,2,3,5])`], + ~definitions=[ + ArrayNumberDist.make("cumprod", r => + r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), + Function.make( + ~name="diff", + ~nameSpace, + ~output=EvtArray, + ~examples=[`diff([3,5,2,3,5])`], + ~definitions=[ + ArrayNumberDist.make("diff", r => + r->E.A.Floats.diff->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + ), + ], + (), + ), +] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res new file mode 100644 index 00000000..92e4ab5f --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res @@ -0,0 +1,55 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +let nameSpace = "PointSet" +let requiresNamespace = true + +let inputsTodist = (inputs: array, makeDist) => { + let array = inputs->getOrError(0)->E.R.bind(Prepare.ToValueArray.Array.openA) + let xyCoords = + array->E.R.bind(xyCoords => + xyCoords + ->E.A2.fmap(xyCoord => + [xyCoord]->Prepare.ToValueArray.Record.twoArgs->E.R.bind(Prepare.ToValueTuple.twoNumbers) + ) + ->E.A.R.firstErrorOrOpen + ) + let expressionValue = + xyCoords + ->E.R.bind(r => r->XYShape.T.makeFromZipped->E.R2.errMap(XYShape.Error.toString)) + ->E.R2.fmap(r => ReducerInterface_InternalExpressionValue.IEvDistribution( + PointSet(makeDist(r)), + )) + expressionValue +} + +let library = [ + Function.make( + ~name="makeContinuous", + ~nameSpace, + ~definitions=[ + FnDefinition.make( + ~requiresNamespace, + ~name="makeContinuous", + ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], + ~run=(_, inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), + (), + ), + ], + (), + ), + Function.make( + ~name="makeDiscrete", + ~nameSpace, + ~definitions=[ + FnDefinition.make( + ~requiresNamespace, + ~name="makeDiscrete", + ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], + ~run=(_, inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), + (), + ), + ], + (), + ), +] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res new file mode 100644 index 00000000..19886841 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res @@ -0,0 +1,90 @@ +open FunctionRegistry_Core + +let nameSpace = "Dist" +let requiresNamespace = false + +let runScoring = (estimate, answer, prior, env) => { + GenericDist.Score.logScore(~estimate, ~answer, ~prior, ~env) + ->E.R2.fmap(FunctionRegistry_Helpers.Wrappers.evNumber) + ->E.R2.errMap(DistributionTypes.Error.toString) +} + +let library = [ + Function.make( + ~name="logScore", + ~nameSpace, + ~output=EvtNumber, + ~examples=[ + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}, prior: normal(5.5,3)})", + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}})", + "Dist.logScore({estimate: normal(5,2), answer: 4.5})", + ], + ~definitions=[ + FnDefinition.make( + ~requiresNamespace, + ~name="logScore", + ~inputs=[ + FRTypeRecord([ + ("estimate", FRTypeDist), + ("answer", FRTypeDistOrNumber), + ("prior", FRTypeDist), + ]), + ], + ~run=(_, inputs, env) => { + switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(inputs) { + | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d)), FRValueDist(prior)]) => + runScoring(estimate, Score_Dist(d), Some(prior), env) + | Ok([ + FRValueDist(estimate), + FRValueDistOrNumber(FRValueNumber(d)), + FRValueDist(prior), + ]) => + runScoring(estimate, Score_Scalar(d), Some(prior), env) + | Error(e) => Error(e) + | _ => Error(FunctionRegistry_Helpers.impossibleError) + } + }, + (), + ), + FnDefinition.make( + ~name="logScore", + ~requiresNamespace, + ~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])], + ~run=(_, inputs, env) => { + switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) { + | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueDist(d))]) => + runScoring(estimate, Score_Dist(d), None, env) + | Ok([FRValueDist(estimate), FRValueDistOrNumber(FRValueNumber(d))]) => + runScoring(estimate, Score_Scalar(d), None, env) + | Error(e) => Error(e) + | _ => Error(FunctionRegistry_Helpers.impossibleError) + } + }, + (), + ), + ], + (), + ), + Function.make( + ~name="klDivergence", + ~nameSpace, + ~output=EvtNumber, + ~examples=["Dist.klDivergence(normal(5,2), normal(5,1.5)"], + ~definitions=[ + FnDefinition.make( + ~name="klDivergence", + ~requiresNamespace, + ~inputs=[FRTypeDist, FRTypeDist], + ~run=(_, inputs, env) => { + switch inputs { + | [FRValueDist(estimate), FRValueDist(d)] => + runScoring(estimate, Score_Dist(d), None, env) + | _ => Error(FunctionRegistry_Helpers.impossibleError) + } + }, + (), + ), + ], + (), + ), +] From d88fb9576748d1236e69015ac78689b64378b7b8 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 16 Jul 2022 18:11:38 -0700 Subject: [PATCH 16/40] Simple reformatting, got RequiresNamespace to work --- .../__tests__/FunctionRegistry_test.res | 5 ++--- .../FunctionRegistry_Core.res | 16 ++++++++------ .../FunctionRegistry_Library.res | 2 +- .../FunctionRegistry/Library/FR_Dict.res | 12 +++++----- .../FunctionRegistry/Library/FR_Dist.res | 9 +++----- .../FunctionRegistry/Library/FR_Fn.res | 2 +- .../FunctionRegistry/Library/FR_List.res | 10 ++++----- .../FunctionRegistry/Library/FR_Number.res | 22 +++++++++++++++++-- .../FunctionRegistry/Library/FR_Pointset.res | 4 ++-- .../FunctionRegistry/Library/FR_Scoring.res | 7 +++--- .../ReducerInterface_ExternalLibrary.res | 9 +++++--- 11 files changed, 58 insertions(+), 40 deletions(-) diff --git a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res index 47d3005a..2909f7d1 100644 --- a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res +++ b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res @@ -18,11 +18,11 @@ module FooImplementation = { let fn = Function.make( ~name="add", ~nameSpace="Foo", + ~requiresNamespace=false, ~examples=["Foo.add(1, 2)", "Foo.add(1, 2, 3)"], ~output=EvtNumber, ~definitions=[ FnDefinition.make( - ~requiresNamespace=false, ~name="add", ~inputs=[FRTypeNumber, FRTypeNumber], ~run=(_, inputs, _) => @@ -33,7 +33,6 @@ module FooImplementation = { (), ), FnDefinition.make( - ~requiresNamespace=true, ~name="add", ~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber], ~run=(_, inputs, _) => @@ -92,4 +91,4 @@ describe("Fn auto-testing", () => { let expectedOutputType = FooImplementation.fn.output |> E.O.toExn("") expect(responseType)->toEqual(Ok(expectedOutputType)) }) -}) \ No newline at end of file +}) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index d2d2a080..887ac3f7 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -41,7 +41,6 @@ and frValueDictParam = (string, frValue) and frValueDistOrNumber = FRValueNumber(float) | FRValueDist(DistributionTypes.genericDist) type fnDefinition = { - requiresNamespace: bool, name: string, inputs: array, run: ( @@ -54,6 +53,7 @@ type fnDefinition = { type function = { name: string, definitions: array, + requiresNamespace: bool, nameSpace: string, output: option, examples: array, @@ -352,9 +352,8 @@ module FnDefinition = { let toLambda = (t: t) => Reducer_Module.convertOptionToFfiFn(t.name, toFfiFn(t))->Reducer_Module.eLambdaFFIValue - let make = (~requiresNamespace=true, ~name, ~inputs, ~run, ()): t => { + let make = (~name, ~inputs, ~run, ()): t => { name: name, - requiresNamespace: requiresNamespace, inputs: inputs, run: run, } @@ -374,6 +373,7 @@ module Function = { let make = ( ~name, ~nameSpace, + ~requiresNamespace, ~definitions, ~examples=?, ~output=?, @@ -387,6 +387,7 @@ module Function = { output: output, examples: examples |> E.O.default([]), isExperimental: isExperimental, + requiresNamespace: requiresNamespace, description: description, } @@ -427,6 +428,9 @@ module NameSpace = { module Registry = { let toJson = (r: registry) => r->E.A2.fmap(Function.toJson) + + let exportedSubset = (r: registry): registry => r |> E.A.filter(r => !r.requiresNamespace) + let definitionsWithFunctions = (r: registry) => r->E.A2.fmap(fn => fn.definitions->E.A2.fmap(def => (def, fn)))->E.A.concatMany @@ -442,7 +446,6 @@ module Registry = { ~env: GenericDist.env, ) => { let matchToDef = m => Matcher.Registry.matchToDef(registry, m) - //Js.log(toSimple(registry)) let showNameMatchDefinitions = matches => { let defs = matches @@ -460,17 +463,16 @@ module Registry = { } } - //todo: get namespace from project. let allNamespaces = (t: registry) => t->E.A2.fmap(r => r.nameSpace)->E.A.uniq let makeModules = (prevBindings: Reducer_Module.t, t: registry): Reducer_Module.t => { let nameSpaces = allNamespaces(t) let nameSpaceBindings = nameSpaces->E.A2.fmap(nameSpace => { - let foo: NameSpace.t = { + let namespaceModule: NameSpace.t = { name: nameSpace, functions: t->E.A2.filter(r => r.nameSpace == nameSpace), } - (nameSpace, NameSpace.toModule(foo)) + (nameSpace, NameSpace.toModule(namespaceModule)) }) E.A.reduce(nameSpaceBindings, prevBindings, (acc, (name, fn)) => acc->Reducer_Module.defineModule(name, fn) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 949837b5..3c74398a 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -5,5 +5,5 @@ let registry = Belt.Array.concatMany([ FR_List.library, FR_Number.library, FR_Pointset.library, - FR_Scoring.library + FR_Scoring.library, ]) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res index c8d28a78..fdb8e191 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res @@ -45,11 +45,11 @@ let library = [ Function.make( ~name="merge", ~nameSpace, + ~requiresNamespace=true, ~output=EvtRecord, ~examples=[`Dict.merge({a: 1, b: 2}, {c: 3, d: 4})`], ~definitions=[ FnDefinition.make( - ~requiresNamespace=true, ~name="merge", ~inputs=[FRTypeDict(FRTypeAny), FRTypeDict(FRTypeAny)], ~run=(inputs, _, _) => { @@ -67,11 +67,11 @@ let library = [ Function.make( ~name="mergeMany", ~nameSpace, + ~requiresNamespace=true, ~output=EvtRecord, ~examples=[`Dict.mergeMany([{a: 1, b: 2}, {c: 3, d: 4}])`], ~definitions=[ FnDefinition.make( - ~requiresNamespace=true, ~name="mergeMany", ~inputs=[FRTypeArray(FRTypeDict(FRTypeAny))], ~run=(_, inputs, _) => @@ -89,11 +89,11 @@ let library = [ Function.make( ~name="keys", ~nameSpace, + ~requiresNamespace=true, ~output=EvtArray, ~examples=[`Dict.keys({a: 1, b: 2})`], ~definitions=[ FnDefinition.make( - ~requiresNamespace=true, ~name="keys", ~inputs=[FRTypeDict(FRTypeAny)], ~run=(inputs, _, _) => @@ -109,11 +109,11 @@ let library = [ Function.make( ~name="values", ~nameSpace, + ~requiresNamespace=true, ~output=EvtArray, ~examples=[`Dict.values({a: 1, b: 2})`], ~definitions=[ FnDefinition.make( - ~requiresNamespace=true, ~name="values", ~inputs=[FRTypeDict(FRTypeAny)], ~run=(inputs, _, _) => @@ -129,11 +129,11 @@ let library = [ Function.make( ~name="toList", ~nameSpace, + ~requiresNamespace=true, ~output=EvtArray, ~examples=[`Dict.toList({a: 1, b: 2})`], ~definitions=[ FnDefinition.make( - ~requiresNamespace=true, ~name="toList", ~inputs=[FRTypeDict(FRTypeAny)], ~run=(inputs, _, _) => @@ -149,11 +149,11 @@ let library = [ Function.make( ~name="fromList", ~nameSpace, + ~requiresNamespace=true, ~output=EvtRecord, ~examples=[`Dict.fromList({a: 1, b: 2})`], ~definitions=[ FnDefinition.make( - ~requiresNamespace=true, ~name="fromList", ~inputs=[FRTypeArray(FRTypeArray(FRTypeAny))], ~run=(inputs, _, _) => diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res index 35e17dd3..424983d8 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dist.res @@ -5,9 +5,10 @@ let twoArgs = E.Tuple2.toFnCall module DistributionCreation = { let nameSpace = "Dist" let output = ReducerInterface_InternalExpressionValue.EvtDistribution + let requiresNamespace = false let fnMake = (~name, ~examples, ~definitions) => { - Function.make(~name, ~nameSpace, ~output, ~examples, ~definitions, ()) + Function.make(~name, ~nameSpace, ~output, ~examples, ~definitions, ~requiresNamespace, ()) } module TwoArgDist = { @@ -18,7 +19,6 @@ module DistributionCreation = { let make = (name, fn) => { FnDefinition.make( - ~requiresNamespace=false, ~name, ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env), @@ -28,7 +28,6 @@ module DistributionCreation = { let makeRecordP5P95 = (name, fn) => { FnDefinition.make( - ~requiresNamespace=false, ~name, ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], ~run=(_, inputs, env) => @@ -40,7 +39,6 @@ module DistributionCreation = { let makeRecordMeanStdev = (name, fn) => { FnDefinition.make( ~name, - ~requiresNamespace=false, ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), @@ -57,7 +55,6 @@ module DistributionCreation = { let make = (name, fn) => FnDefinition.make( - ~requiresNamespace=false, ~name, ~inputs=[FRTypeDistOrNumber], ~run=(_, inputs, env) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env), @@ -152,4 +149,4 @@ module DistributionCreation = { ] } -let library = DistributionCreation.library \ No newline at end of file +let library = DistributionCreation.library diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res index b30cac2d..1e423f52 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res @@ -34,6 +34,7 @@ let library = [ Function.make( ~name="declare", ~nameSpace, + ~requiresNamespace=true, ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", ~examples=[ `declareFn({ @@ -47,7 +48,6 @@ let library = [ ~isExperimental=true, ~definitions=[ FnDefinition.make( - ~requiresNamespace=true, ~name="declare", ~inputs=[Declaration.frType], ~run=(_, inputs, _) => { diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res index 9c064966..25924232 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_List.res @@ -29,12 +29,12 @@ let library = [ Function.make( ~name="make", ~nameSpace, + ~requiresNamespace, ~output=EvtArray, ~examples=[`List.make(2, "testValue")`], ~definitions=[ //Todo: If the second item is a function with no args, it could be nice to run this function and return the result. FnDefinition.make( - ~requiresNamespace, ~name="make", ~inputs=[FRTypeNumber, FRTypeAny], ~run=(inputs, _, _) => { @@ -51,11 +51,11 @@ let library = [ Function.make( ~name="upTo", ~nameSpace, + ~requiresNamespace, ~output=EvtArray, ~examples=[`List.upTo(1,4)`], ~definitions=[ FnDefinition.make( - ~requiresNamespace, ~name="upTo", ~inputs=[FRTypeNumber, FRTypeNumber], ~run=(_, inputs, _) => @@ -70,10 +70,10 @@ let library = [ Function.make( ~name="first", ~nameSpace, + ~requiresNamespace, ~examples=[`List.first([1,4,5])`], ~definitions=[ FnDefinition.make( - ~requiresNamespace, ~name="first", ~inputs=[FRTypeArray(FRTypeAny)], ~run=(inputs, _, _) => @@ -89,10 +89,10 @@ let library = [ Function.make( ~name="last", ~nameSpace, + ~requiresNamespace, ~examples=[`List.last([1,4,5])`], ~definitions=[ FnDefinition.make( - ~requiresNamespace=false, ~name="last", ~inputs=[FRTypeArray(FRTypeAny)], ~run=(inputs, _, _) => @@ -109,10 +109,10 @@ let library = [ ~name="reverse", ~nameSpace, ~output=EvtArray, + ~requiresNamespace=false, ~examples=[`List.reverse([1,4,5])`], ~definitions=[ FnDefinition.make( - ~requiresNamespace=false, ~name="reverse", ~inputs=[FRTypeArray(FRTypeAny)], ~run=(inputs, _, _) => diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res index 0dba4c9a..10d5d1f2 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res @@ -7,7 +7,6 @@ let requiresNamespace = false module NumberToNumber = { let make = (name, fn) => FnDefinition.make( - ~requiresNamespace, ~name, ~inputs=[FRTypeNumber], ~run=(_, inputs, _) => { @@ -24,7 +23,6 @@ module NumberToNumber = { module ArrayNumberDist = { let make = (name, fn) => { FnDefinition.make( - ~requiresNamespace=false, ~name, ~inputs=[FRTypeArray(FRTypeNumber)], ~run=(_, inputs, _) => @@ -51,6 +49,7 @@ let library = [ Function.make( ~name="floor", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`floor(3.5)`], ~definitions=[NumberToNumber.make("floor", Js.Math.floor_float)], @@ -59,6 +58,7 @@ let library = [ Function.make( ~name="ceiling", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`ceiling(3.5)`], ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], @@ -67,6 +67,7 @@ let library = [ Function.make( ~name="absolute value", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`abs(3.5)`], ~definitions=[NumberToNumber.make("abs", Js.Math.abs_float)], @@ -75,6 +76,7 @@ let library = [ Function.make( ~name="exponent", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`exp(3.5)`], ~definitions=[NumberToNumber.make("exp", Js.Math.exp)], @@ -83,6 +85,7 @@ let library = [ Function.make( ~name="log", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`log(3.5)`], ~definitions=[NumberToNumber.make("log", Js.Math.log)], @@ -91,6 +94,7 @@ let library = [ Function.make( ~name="log base 10", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`log10(3.5)`], ~definitions=[NumberToNumber.make("log10", Js.Math.log10)], @@ -99,6 +103,7 @@ let library = [ Function.make( ~name="log base 2", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`log2(3.5)`], ~definitions=[NumberToNumber.make("log2", Js.Math.log2)], @@ -107,6 +112,7 @@ let library = [ Function.make( ~name="round", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`round(3.5)`], ~definitions=[NumberToNumber.make("round", Js.Math.round)], @@ -115,6 +121,7 @@ let library = [ Function.make( ~name="sum", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`sum([3,5,2])`], ~definitions=[ArrayNumberDist.make("sum", r => r->E.A.Floats.sum->Wrappers.evNumber->Ok)], @@ -123,6 +130,7 @@ let library = [ Function.make( ~name="product", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`product([3,5,2])`], ~definitions=[ @@ -133,6 +141,7 @@ let library = [ Function.make( ~name="min", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`min([3,5,2])`], ~definitions=[ArrayNumberDist.make("min", r => r->E.A.Floats.min->Wrappers.evNumber->Ok)], @@ -141,6 +150,7 @@ let library = [ Function.make( ~name="max", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`max([3,5,2])`], ~definitions=[ArrayNumberDist.make("max", r => r->E.A.Floats.max->Wrappers.evNumber->Ok)], @@ -149,6 +159,7 @@ let library = [ Function.make( ~name="mean", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`mean([3,5,2])`], ~definitions=[ArrayNumberDist.make("mean", r => r->E.A.Floats.mean->Wrappers.evNumber->Ok)], @@ -157,6 +168,7 @@ let library = [ Function.make( ~name="geometric mean", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`geomean([3,5,2])`], ~definitions=[ @@ -167,6 +179,7 @@ let library = [ Function.make( ~name="standard deviation", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`stdev([3,5,2,3,5])`], ~definitions=[ArrayNumberDist.make("stdev", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok)], @@ -175,6 +188,7 @@ let library = [ Function.make( ~name="variance", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[`variance([3,5,2,3,5])`], ~definitions=[ @@ -185,6 +199,7 @@ let library = [ Function.make( ~name="sort", ~nameSpace, + ~requiresNamespace, ~output=EvtArray, ~examples=[`sort([3,5,2,3,5])`], ~definitions=[ @@ -197,6 +212,7 @@ let library = [ Function.make( ~name="cumulative sum", ~nameSpace, + ~requiresNamespace, ~output=EvtArray, ~examples=[`cumsum([3,5,2,3,5])`], ~definitions=[ @@ -209,6 +225,7 @@ let library = [ Function.make( ~name="cumulative prod", ~nameSpace, + ~requiresNamespace, ~output=EvtArray, ~examples=[`cumprod([3,5,2,3,5])`], ~definitions=[ @@ -221,6 +238,7 @@ let library = [ Function.make( ~name="diff", ~nameSpace, + ~requiresNamespace, ~output=EvtArray, ~examples=[`diff([3,5,2,3,5])`], ~definitions=[ diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res index 92e4ab5f..9a0745c1 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res @@ -27,9 +27,9 @@ let library = [ Function.make( ~name="makeContinuous", ~nameSpace, + ~requiresNamespace, ~definitions=[ FnDefinition.make( - ~requiresNamespace, ~name="makeContinuous", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], ~run=(_, inputs, _) => inputsTodist(inputs, r => Continuous(Continuous.make(r))), @@ -41,9 +41,9 @@ let library = [ Function.make( ~name="makeDiscrete", ~nameSpace, + ~requiresNamespace, ~definitions=[ FnDefinition.make( - ~requiresNamespace, ~name="makeDiscrete", ~inputs=[FRTypeArray(FRTypeRecord([("x", FRTypeNumeric), ("y", FRTypeNumeric)]))], ~run=(_, inputs, _) => inputsTodist(inputs, r => Discrete(Discrete.make(r))), diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res index 19886841..0ba1f5c3 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res @@ -1,7 +1,7 @@ open FunctionRegistry_Core let nameSpace = "Dist" -let requiresNamespace = false +let requiresNamespace = true let runScoring = (estimate, answer, prior, env) => { GenericDist.Score.logScore(~estimate, ~answer, ~prior, ~env) @@ -13,6 +13,7 @@ let library = [ Function.make( ~name="logScore", ~nameSpace, + ~requiresNamespace, ~output=EvtNumber, ~examples=[ "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}, prior: normal(5.5,3)})", @@ -21,7 +22,6 @@ let library = [ ], ~definitions=[ FnDefinition.make( - ~requiresNamespace, ~name="logScore", ~inputs=[ FRTypeRecord([ @@ -48,7 +48,6 @@ let library = [ ), FnDefinition.make( ~name="logScore", - ~requiresNamespace, ~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])], ~run=(_, inputs, env) => { switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(inputs) { @@ -69,11 +68,11 @@ let library = [ ~name="klDivergence", ~nameSpace, ~output=EvtNumber, + ~requiresNamespace, ~examples=["Dist.klDivergence(normal(5,2), normal(5,1.5)"], ~definitions=[ FnDefinition.make( ~name="klDivergence", - ~requiresNamespace, ~inputs=[FRTypeDist, FRTypeDist], ~run=(_, inputs, env) => { switch inputs { diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res index 3e6172c9..c9b72b69 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res @@ -18,9 +18,12 @@ type internalExpressionValue = InternalExpressionValue.t let registry = FunctionRegistry_Library.registry let tryRegistry = ((fnName, args): InternalExpressionValue.functionCall, env) => { - FunctionRegistry_Core.Registry.matchAndRun(~registry, ~fnName, ~args, ~env)->E.O2.fmap( - E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), - ) + FunctionRegistry_Core.Registry.matchAndRun( + ~registry=FunctionRegistry_Core.Registry.exportedSubset(registry), + ~fnName, + ~args, + ~env, + )->E.O2.fmap(E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s))) } let dispatch = (call: InternalExpressionValue.functionCall, environment, chain): result< From 5e8b46b7df7d7d5e724f44a263260308457e0306 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 16 Jul 2022 19:06:48 -0700 Subject: [PATCH 17/40] Cleaning up Function Registry to Reducer interface --- .../__tests__/FunctionRegistry_test.res | 3 +- .../FunctionRegistry_Core.res | 12 ++++-- .../FunctionRegistry_Library.res | 2 + .../ReducerInterface_ExternalLibrary.res | 40 +------------------ .../ReducerInterface_StdLib.res | 5 ++- .../SquiggleLibrary/SquiggleLibrary_Math.res | 4 +- 6 files changed, 18 insertions(+), 48 deletions(-) diff --git a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res index 2909f7d1..376f8c86 100644 --- a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res +++ b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res @@ -50,8 +50,7 @@ module FooImplementation = { let library = [fn] } -let makeBindings = (previousBindings: Bindings.t): Bindings.t => - previousBindings->FunctionRegistry_Core.Registry.makeModules(FooImplementation.library) +let makeBindings = FunctionRegistry_Core.Registry.makeBindings(_, FooImplementation.library) let stdLibWithFoo = Bindings.emptyBindings->makeBindings diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 887ac3f7..1af459f9 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -429,7 +429,7 @@ module NameSpace = { module Registry = { let toJson = (r: registry) => r->E.A2.fmap(Function.toJson) - let exportedSubset = (r: registry): registry => r |> E.A.filter(r => !r.requiresNamespace) + let _exportedSubset = (r: registry): registry => r |> E.A.filter(r => !r.requiresNamespace) let definitionsWithFunctions = (r: registry) => r->E.A2.fmap(fn => fn.definitions->E.A2.fmap(def => (def, fn)))->E.A.concatMany @@ -439,7 +439,7 @@ module Registry = { to the registry, then it's possible that there could be a match after the registry is called. However, for now, we could just call the registry last. */ - let matchAndRun = ( + let _matchAndRun = ( ~registry: registry, ~fnName: string, ~args: array, @@ -463,9 +463,15 @@ module Registry = { } } + let dispatch = (registry, (fnName, args): ReducerInterface_InternalExpressionValue.functionCall, env) => { + _matchAndRun(~registry=_exportedSubset(registry), ~fnName, ~args, ~env)->E.O2.fmap( + E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), + ) + } + let allNamespaces = (t: registry) => t->E.A2.fmap(r => r.nameSpace)->E.A.uniq - let makeModules = (prevBindings: Reducer_Module.t, t: registry): Reducer_Module.t => { + let makeBindings = (prevBindings: Reducer_Module.t, t: registry): Reducer_Module.t => { let nameSpaces = allNamespaces(t) let nameSpaceBindings = nameSpaces->E.A2.fmap(nameSpace => { let namespaceModule: NameSpace.t = { diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 3c74398a..6c8d1bb0 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -7,3 +7,5 @@ let registry = Belt.Array.concatMany([ FR_Pointset.library, FR_Scoring.library, ]) + +let dispatch = FunctionRegistry_Core.Registry.dispatch(registry) \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res index c9b72b69..312dfd38 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res @@ -1,31 +1,9 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue - type internalExpressionValue = InternalExpressionValue.t -// module Sample = { -// // In real life real libraries should be somewhere else -// /* -// For an example of mapping polymorphic custom functions. To be deleted after real integration -// */ -// let customAdd = (a: float, b: float): float => {a +. b} -// } - /* Map external calls of Reducer */ - -// I expect that it's important to build this first, so it doesn't get recalculated for each tryRegistry() call. -let registry = FunctionRegistry_Library.registry - -let tryRegistry = ((fnName, args): InternalExpressionValue.functionCall, env) => { - FunctionRegistry_Core.Registry.matchAndRun( - ~registry=FunctionRegistry_Core.Registry.exportedSubset(registry), - ~fnName, - ~args, - ~env, - )->E.O2.fmap(E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s))) -} - let dispatch = (call: InternalExpressionValue.functionCall, environment, chain): result< internalExpressionValue, 'e, @@ -35,22 +13,6 @@ let dispatch = (call: InternalExpressionValue.functionCall, environment, chain): () => ReducerInterface_Date.dispatch(call, environment), () => ReducerInterface_Duration.dispatch(call, environment), () => ReducerInterface_Number.dispatch(call, environment), - () => tryRegistry(call, environment), + () => FunctionRegistry_Library.dispatch(call, environment), ])->E.O2.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. - -The final chain(call) invokes the builtin default functions of the interpreter. - -Via chain(call), all MathJs operators and functions are available for string, number , boolean, array and record - .e.g + - / * > >= < <= == /= not and or sin cos log ln concat, etc. - -// See https://mathjs.org/docs/expressions/syntax.html -// See https://mathjs.org/docs/reference/functions.html - -Remember from the users point of view, there are no different modules: -// "doSth( constructorType1 )" -// "doSth( constructorType2 )" -doSth gets dispatched to the correct module because of the type signature. You get function and operator abstraction for free. You don't need to combine different implementations into one type. That would be duplicating the repsonsibility of the dispatcher. -*/ diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res index c08b7cb1..ae9d4c55 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res @@ -1,6 +1,9 @@ module Module = Reducer_Module -let internalStdLib = Module.emptyModule->SquiggleLibrary_Math.makeBindings +let internalStdLib = + Module.emptyModule + ->SquiggleLibrary_Math.makeBindings + ->FunctionRegistry_Core.Registry.makeBindings(FunctionRegistry_Library.registry) @genType let externalStdLib = internalStdLib->Module.toTypeScriptBindings diff --git a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res index b7b925ed..c96a8f82 100644 --- a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res +++ b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res @@ -21,6 +21,4 @@ let mathBindings: Bindings.t = //TODO: This should be in a different place. let makeBindings = (previousBindings: Bindings.t): Bindings.t => - previousBindings - ->Bindings.defineModule("Math", mathBindings) - ->FunctionRegistry_Core.Registry.makeModules(FunctionRegistry_Library.registry) + previousBindings->Bindings.defineModule("Math", mathBindings) \ No newline at end of file From 395477ed120b43d359fa9acf20b6baa39643b8b3 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 16 Jul 2022 19:50:18 -0700 Subject: [PATCH 18/40] Initial testing of FunctionRegistry Library --- .../__tests__/FunctionRegistry_test.res | 14 +++++----- ...leLibrary_FunctionRegistryLibrary_test.res | 27 +++++++++++++++++++ .../FunctionRegistry_Core.res | 9 ++++++- ...ducerInterface_InternalExpressionValue.res | 20 ++++++++++++++ 4 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res diff --git a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res index 376f8c86..bfb4ab9f 100644 --- a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res +++ b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res @@ -15,15 +15,15 @@ module FooImplementation = { open FunctionRegistry_Core open FunctionRegistry_Helpers - let fn = Function.make( + let fn1 = Function.make( ~name="add", ~nameSpace="Foo", ~requiresNamespace=false, - ~examples=["Foo.add(1, 2)", "Foo.add(1, 2, 3)"], + ~examples=["Foo.add2(1, 2)", "Foo.add3(1, 2, 3)"], ~output=EvtNumber, ~definitions=[ FnDefinition.make( - ~name="add", + ~name="add2", ~inputs=[FRTypeNumber, FRTypeNumber], ~run=(_, inputs, _) => switch inputs { @@ -33,7 +33,7 @@ module FooImplementation = { (), ), FnDefinition.make( - ~name="add", + ~name="add3", ~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber], ~run=(_, inputs, _) => switch inputs { @@ -47,7 +47,7 @@ module FooImplementation = { (), ) - let library = [fn] + let library = [fn1] } let makeBindings = FunctionRegistry_Core.Registry.makeBindings(_, FooImplementation.library) @@ -78,7 +78,7 @@ describe("Module", () => { }) describe("Fn auto-testing", () => { - let items = FooImplementation.fn.examples->E.A.to_list + let items = FooImplementation.fn1.examples->E.A.to_list testAll("tests of validity", items, r => { expect(r->evalWithFoo->E.R.isOk)->toEqual(true) @@ -87,7 +87,7 @@ describe("Fn auto-testing", () => { testAll("tests of type", items, r => { let responseType = r->evalWithFoo->E.R2.fmap(ReducerInterface_InternalExpressionValue.valueToValueType) - let expectedOutputType = FooImplementation.fn.output |> E.O.toExn("") + let expectedOutputType = FooImplementation.fn1.output |> E.O.toExn("") expect(responseType)->toEqual(Ok(expectedOutputType)) }) }) diff --git a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res new file mode 100644 index 00000000..23e83a45 --- /dev/null +++ b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res @@ -0,0 +1,27 @@ +open Jest +open Expect + +let expectEvalToBeOk = (expr: string) => + Reducer.evaluate(expr)->Reducer_Helpers.rRemoveDefaultsExternal->E.R.isOk->expect->toBe(true) + +let registry = FunctionRegistry_Library.registry +let examples = E.A.to_list(FunctionRegistry_Core.Registry.allExamples(registry)) + +describe("Fn auto-testing", () => { + testAll("tests of validity", examples, r => { + expectEvalToBeOk(r) + }) + + // testAll( + // "tests of type", + // E.A.to_list(FunctionRegistry_Core.Registry.allExamplesWithFns(registry)), + // ((fn, example)) => { + // let responseType = + // example + // ->Reducer.evaluate + // ->E.R2.fmap(ReducerInterface_InternalExpressionValue.externalValueToValueType) + // let expectedOutputType = fn.output |> E.O.toExn("") + // expect(responseType)->toEqual(Ok(expectedOutputType)) + // }, + // ) +}) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 1af459f9..f35bbb5e 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -429,6 +429,9 @@ module NameSpace = { module Registry = { let toJson = (r: registry) => r->E.A2.fmap(Function.toJson) + let allExamples = (r: registry) => r->E.A2.fmap(r => r.examples)->E.A.concatMany + let allExamplesWithFns = (r: registry) => r->E.A2.fmap(fn => (fn.examples->E.A2.fmap(example => (fn, example))))->E.A.concatMany + let _exportedSubset = (r: registry): registry => r |> E.A.filter(r => !r.requiresNamespace) let definitionsWithFunctions = (r: registry) => @@ -463,7 +466,11 @@ module Registry = { } } - let dispatch = (registry, (fnName, args): ReducerInterface_InternalExpressionValue.functionCall, env) => { + let dispatch = ( + registry, + (fnName, args): ReducerInterface_InternalExpressionValue.functionCall, + env, + ) => { _matchAndRun(~registry=_exportedSubset(registry), ~fnName, ~args, ~env)->E.O2.fmap( E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), ) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res index a6766071..3beea889 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res @@ -160,6 +160,26 @@ let valueToValueType = value => | IEvTypeIdentifier(_) => EvtTypeIdentifier } +let externalValueToValueType = (value: ExternalExpressionValue.t) => + switch value { + | EvArray(_) => EvtArray + | EvArrayString(_) => EvtArrayString + | EvBool(_) => EvtBool + | EvCall(_) => EvtCall + | EvDate(_) => EvtDate + | EvDeclaration(_) => EvtDeclaration + | EvDistribution(_) => EvtDistribution + | EvLambda(_) => EvtLambda + | EvModule(_) => EvtModule + | EvNumber(_) => EvtNumber + | EvRecord(_) => EvtRecord + | EvString(_) => EvtString + | EvSymbol(_) => EvtSymbol + | EvTimeDuration(_) => EvtTimeDuration + | EvType(_) => EvtType + | EvTypeIdentifier(_) => EvtTypeIdentifier + } + let functionCallToCallSignature = (functionCall: functionCall): functionCallSignature => { let (fn, args) = functionCall CallSignature(fn, args->Js.Array2.map(valueToValueType)) From c5447b8d7ab9186c6a93031bb535c4052677c297 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 16 Jul 2022 20:32:37 -0700 Subject: [PATCH 19/40] All autogenerated FunctionLibrary tests pass --- .../__tests__/FunctionRegistry_test.res | 8 +++--- ...leLibrary_FunctionRegistryLibrary_test.res | 28 +++++++++++-------- .../FunctionRegistry/Library/FR_Dict.res | 2 +- .../FunctionRegistry/Library/FR_Fn.res | 3 +- .../FunctionRegistry/Library/FR_Number.res | 2 +- .../FunctionRegistry/Library/FR_Scoring.res | 6 ++-- 6 files changed, 27 insertions(+), 22 deletions(-) diff --git a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res index bfb4ab9f..d68d9b01 100644 --- a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res +++ b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res @@ -67,12 +67,12 @@ let evalToStringResultWithFoo = sourceCode => evalWithFoo(sourceCode)->InternalExpressionValue.toStringResult describe("Module", () => { - test("add(1,2)", () => { - let result = evalToStringResultWithFoo("Foo.add(1,2)") + test("add2(1,2)", () => { + let result = evalToStringResultWithFoo("Foo.add2(1,2)") expect(result)->toEqual("Ok(3)") }) - test("add(1,2,3)", () => { - let result = evalToStringResultWithFoo("Foo.add(1,2,3)") + test("add3(1,2,3)", () => { + let result = evalToStringResultWithFoo("Foo.add3(1,2,3)") expect(result)->toEqual("Ok(6)") }) }) diff --git a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res index 23e83a45..a3b73d2b 100644 --- a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res +++ b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res @@ -12,16 +12,20 @@ describe("Fn auto-testing", () => { expectEvalToBeOk(r) }) - // testAll( - // "tests of type", - // E.A.to_list(FunctionRegistry_Core.Registry.allExamplesWithFns(registry)), - // ((fn, example)) => { - // let responseType = - // example - // ->Reducer.evaluate - // ->E.R2.fmap(ReducerInterface_InternalExpressionValue.externalValueToValueType) - // let expectedOutputType = fn.output |> E.O.toExn("") - // expect(responseType)->toEqual(Ok(expectedOutputType)) - // }, - // ) + testAll( + "tests of type", + E.A.to_list( + FunctionRegistry_Core.Registry.allExamplesWithFns(registry)->E.A2.filter(((fn, _)) => + E.O.isSome(fn.output) + ), + ), + ((fn, example)) => { + let responseType = + example + ->Reducer.evaluate + ->E.R2.fmap(ReducerInterface_InternalExpressionValue.externalValueToValueType) + let expectedOutputType = fn.output |> E.O.toExn("") + expect(responseType)->toEqual(Ok(expectedOutputType)) + }, + ) }) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res index fdb8e191..4a52f187 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Dict.res @@ -151,7 +151,7 @@ let library = [ ~nameSpace, ~requiresNamespace=true, ~output=EvtRecord, - ~examples=[`Dict.fromList({a: 1, b: 2})`], + ~examples=[`Dict.fromList([["a", 1], ["b", 2]])`], ~definitions=[ FnDefinition.make( ~name="fromList", diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res index 1e423f52..512d564a 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Fn.res @@ -35,9 +35,10 @@ let library = [ ~name="declare", ~nameSpace, ~requiresNamespace=true, + ~output=EvtDeclaration, ~description="Adds metadata to a function of the input ranges. Works now for numeric and date inputs. This is useful when making predictions. It allows you to limit the domain that your prediction will be used and scored within.", ~examples=[ - `declareFn({ + `Function.declare({ fn: {|a,b| a }, inputs: [ {min: 0, max: 100}, diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res index 10d5d1f2..6bf9ff9e 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res @@ -60,7 +60,7 @@ let library = [ ~nameSpace, ~requiresNamespace, ~output=EvtNumber, - ~examples=[`ceiling(3.5)`], + ~examples=[`ceil(3.5)`], ~definitions=[NumberToNumber.make("ceil", Js.Math.ceil_float)], (), ), diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res index 0ba1f5c3..d8d5ddd0 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Scoring.res @@ -16,8 +16,8 @@ let library = [ ~requiresNamespace, ~output=EvtNumber, ~examples=[ - "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}, prior: normal(5.5,3)})", - "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)}})", + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1), prior: normal(5.5,3)})", + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)})", "Dist.logScore({estimate: normal(5,2), answer: 4.5})", ], ~definitions=[ @@ -69,7 +69,7 @@ let library = [ ~nameSpace, ~output=EvtNumber, ~requiresNamespace, - ~examples=["Dist.klDivergence(normal(5,2), normal(5,1.5)"], + ~examples=["Dist.klDivergence(normal(5,2), normal(5,1.5))"], ~definitions=[ FnDefinition.make( ~name="klDivergence", From b502e21a0f606c525a35a7a54aa0ad448654337d Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 16 Jul 2022 20:33:15 -0700 Subject: [PATCH 20/40] Format --- .../src/rescript/FunctionRegistry/FunctionRegistry_Core.res | 3 ++- .../src/rescript/FunctionRegistry/FunctionRegistry_Library.res | 2 +- .../src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index f35bbb5e..85cf5609 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -430,7 +430,8 @@ module Registry = { let toJson = (r: registry) => r->E.A2.fmap(Function.toJson) let allExamples = (r: registry) => r->E.A2.fmap(r => r.examples)->E.A.concatMany - let allExamplesWithFns = (r: registry) => r->E.A2.fmap(fn => (fn.examples->E.A2.fmap(example => (fn, example))))->E.A.concatMany + let allExamplesWithFns = (r: registry) => + r->E.A2.fmap(fn => fn.examples->E.A2.fmap(example => (fn, example)))->E.A.concatMany let _exportedSubset = (r: registry): registry => r |> E.A.filter(r => !r.requiresNamespace) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 6c8d1bb0..52a424e0 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -8,4 +8,4 @@ let registry = Belt.Array.concatMany([ FR_Scoring.library, ]) -let dispatch = FunctionRegistry_Core.Registry.dispatch(registry) \ No newline at end of file +let dispatch = FunctionRegistry_Core.Registry.dispatch(registry) diff --git a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res index c96a8f82..d719afd0 100644 --- a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res +++ b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res @@ -21,4 +21,4 @@ let mathBindings: Bindings.t = //TODO: This should be in a different place. let makeBindings = (previousBindings: Bindings.t): Bindings.t => - previousBindings->Bindings.defineModule("Math", mathBindings) \ No newline at end of file + previousBindings->Bindings.defineModule("Math", mathBindings) From 08a7b8586bf797b7252242d43e1bebb565dd731c Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 16 Jul 2022 22:01:26 -0700 Subject: [PATCH 21/40] Simple tests for function library --- ...leLibrary_FunctionRegistryLibrary_test.res | 47 +++++++++++++++++++ packages/squiggle-lang/package.json | 1 - .../FunctionRegistry/Library/FR_Number.res | 6 +-- .../squiggle-lang/src/rescript/Utility/E.res | 2 +- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res index a3b73d2b..77052d9b 100644 --- a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res +++ b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res @@ -1,5 +1,6 @@ open Jest open Expect +open Reducer_TestHelpers let expectEvalToBeOk = (expr: string) => Reducer.evaluate(expr)->Reducer_Helpers.rRemoveDefaultsExternal->E.R.isOk->expect->toBe(true) @@ -29,3 +30,49 @@ describe("Fn auto-testing", () => { }, ) }) + +describe("FunctionRegistry Library", () => { + testEvalToBe("List.make(3, 'HI')", "Ok(['HI','HI','HI'])") + testEvalToBe("make(3, 'HI')", "Error(Function not found: make(Number,String))") + testEvalToBe("List.upTo(1,3)", "Ok([1,2,3])") + testEvalToBe("List.first([3,5,8])", "Ok(3)") + testEvalToBe("List.last([3,5,8])", "Ok(8)") + testEvalToBe("List.reverse([3,5,8])", "Ok([8,5,3])") + testEvalToBe("Dist.normal(5,2)", "Ok(Normal(5,2))") + testEvalToBe("normal(5,2)", "Ok(Normal(5,2))") + testEvalToBe("normal({mean:5,stdev:2})", "Ok(Normal(5,2))") + testEvalToBe("-2 to 4", "Ok(Normal(1,1.8238704957353074))") + testEvalToBe("pointMass(5)", "Ok(PointMass(5))") + testEvalToBe("Number.floor(5.5)", "Ok(5)") + testEvalToBe("Number.ceil(5.5)", "Ok(6)") + testEvalToBe("floor(5.5)", "Ok(5)") + testEvalToBe("ceil(5.5)", "Ok(6)") + testEvalToBe("Number.abs(5.5)", "Ok(5.5)") + testEvalToBe("abs(5.5)", "Ok(5.5)") + testEvalToBe("Number.exp(10)", "Ok(22026.465794806718)") + testEvalToBe("Number.log10(10)", "Ok(1)") + testEvalToBe("Number.log2(10)", "Ok(3.321928094887362)") + testEvalToBe("Number.sum([2,5,3])", "Ok(10)") + testEvalToBe("sum([2,5,3])", "Ok(10)") + testEvalToBe("Number.product([2,5,3])", "Ok(30)") + testEvalToBe("Number.min([2,5,3])", "Ok(2)") + testEvalToBe("Number.max([2,5,3])", "Ok(5)") + testEvalToBe("Number.mean([0,5,10])", "Ok(5)") + testEvalToBe("Number.geomean([1,5,18])", "Ok(4.481404746557164)") + testEvalToBe("Number.stdev([0,5,10,15])", "Ok(5.5901699437494745)") + testEvalToBe("Number.variance([0,5,10,15])", "Ok(31.25)") + testEvalToBe("Number.sort([10,0,15,5])", "Ok([0,5,10,15])") + testEvalToBe("Number.cumsum([1,5,3])", "Ok([1,6,9])") + testEvalToBe("Number.cumprod([1,5,3])", "Ok([1,5,15])") + testEvalToBe("Number.diff([1,5,3])", "Ok([4,-2])") + testEvalToBe( + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1), prior: normal(5.5,3)})", + "Ok(-0.33591375663884876)", + ) + testEvalToBe( + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)})", + "Ok(0.32244107041564646)", + ) + testEvalToBe("Dist.logScore({estimate: normal(5,2), answer: 4.5})", "Ok(1.6433360626394853)") + testEvalToBe("Dist.klDivergence(normal(5,2), normal(5,1.5))", "Ok(0.06874342818671068)") +}) diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index ba6449ce..b2067205 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -15,7 +15,6 @@ "start": "rescript build -w -with-deps", "clean": "rescript clean && rm -rf dist", "test:reducer": "jest __tests__/Reducer*/", - "test:reducer2": "jest __tests__/FunctionRegistry_test", "benchmark": "ts-node benchmark/conversion_tests.ts", "test": "jest", "test:ts": "jest __tests__/TS/", diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res index 6bf9ff9e..c7027f06 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Number.res @@ -192,7 +192,7 @@ let library = [ ~output=EvtNumber, ~examples=[`variance([3,5,2,3,5])`], ~definitions=[ - ArrayNumberDist.make("variance", r => r->E.A.Floats.stdev->Wrappers.evNumber->Ok), + ArrayNumberDist.make("variance", r => r->E.A.Floats.variance->Wrappers.evNumber->Ok), ], (), ), @@ -217,7 +217,7 @@ let library = [ ~examples=[`cumsum([3,5,2,3,5])`], ~definitions=[ ArrayNumberDist.make("cumsum", r => - r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + r->E.A.Floats.cumSum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok ), ], (), @@ -230,7 +230,7 @@ let library = [ ~examples=[`cumprod([3,5,2,3,5])`], ~definitions=[ ArrayNumberDist.make("cumprod", r => - r->E.A.Floats.cumsum->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok + r->E.A.Floats.cumProd->E.A2.fmap(Wrappers.evNumber)->Wrappers.evArray->Ok ), ], (), diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index fd328a1c..eba85545 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -752,7 +752,7 @@ module A = { let diff = (t: t): array => Belt.Array.zipBy(t, Belt.Array.sliceToEnd(t, 1), (left, right) => right -. left) - let cumsum = (t: t): array => accumulate((a, b) => a +. b, t) + let cumSum = (t: t): array => accumulate((a, b) => a +. b, t) let cumProd = (t: t): array => accumulate((a, b) => a *. b, t) exception RangeError(string) From 8fb75d57fc2b3617b7b2fa8ecdfed117698b9d7e Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 18 Jul 2022 10:27:41 +0200 Subject: [PATCH 22/40] type check --- ...educer_Type_TypeChecker_arguments_test.res | 52 +++++ .../Reducer_Type_TypeChecker_test.res | 78 +++++++ .../Reducer_Dispatch_BuiltInMacros.res | 2 +- .../rescript/Reducer/Reducer_ErrorValue.res | 4 +- .../Reducer_Type/Reducer_Type_Modifiers.res | 53 +++++ .../Reducer/Reducer_Type/Reducer_Type_T.res | 1 + .../Reducer_Type/Reducer_Type_TypeChecker.res | 191 +++++++++++++----- 7 files changed, 331 insertions(+), 50 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res create mode 100644 packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Modifiers.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res new file mode 100644 index 00000000..4f490bd5 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res @@ -0,0 +1,52 @@ +module Expression = Reducer_Expression +module ExpressionT = Reducer_Expression_T +module ErrorValue = Reducer_ErrorValue +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Module = Reducer_Module +module T = Reducer_Type_T +module TypeChecker = Reducer_Type_TypeChecker + +open Jest +open Expect + +let checkArgumentsSourceCode = (aTypeSourceCode: string, sourceCode: string): result< + 'v, + ErrorValue.t, +> => { + let reducerFn = Expression.reduceExpression + let rResult = + Reducer.parse(sourceCode)->Belt.Result.flatMap(expr => + reducerFn(expr, Module.emptyBindings, InternalExpressionValue.defaultEnvironment) + ) + rResult->Belt.Result.flatMap(result => + switch result { + | IEvArray(args) => TypeChecker.checkArguments(aTypeSourceCode, args, reducerFn) + | _ => Js.Exn.raiseError("Arguments has to be an array") + } + ) +} + +let myCheckArguments = (aTypeSourceCode: string, sourceCode: string): string => + switch checkArgumentsSourceCode(aTypeSourceCode, sourceCode) { + | Ok(_) => "Ok" + | Error(error) => ErrorValue.errorToString(error) + } + +let myCheckArgumentsExpectEqual = (aTypeSourceCode, sourceCode, answer) => + expect(myCheckArguments(aTypeSourceCode, sourceCode))->toEqual(answer) + +let _myCheckArgumentsTest = (test, aTypeSourceCode, sourceCode, answer) => + test(aTypeSourceCode, () => myCheckArgumentsExpectEqual(aTypeSourceCode, sourceCode, answer)) + +let myCheckArgumentsTest = (aTypeSourceCode, sourceCode, answer) => + _myCheckArgumentsTest(test, aTypeSourceCode, sourceCode, answer) +module MySkip = { + let myCheckArgumentsTest = (aTypeSourceCode, sourceCode, answer) => + _myCheckArgumentsTest(Skip.test, aTypeSourceCode, sourceCode, answer) +} +module MyOnly = { + let myCheckArgumentsTest = (aTypeSourceCode, sourceCode, answer) => + _myCheckArgumentsTest(Only.test, aTypeSourceCode, sourceCode, answer) +} + +myCheckArgumentsTest("number=>number=>number", "[1,2]", "Ok") diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res new file mode 100644 index 00000000..5b093060 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res @@ -0,0 +1,78 @@ +module Expression = Reducer_Expression +module ExpressionT = Reducer_Expression_T +module ErrorValue = Reducer_ErrorValue +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Module = Reducer_Module +module T = Reducer_Type_T +module TypeChecker = Reducer_Type_TypeChecker + +open Jest +open Expect + +// In development, you are expected to use TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn). +// isTypeOfSourceCode is written to use strings instead of expression values. + +let isTypeOfSourceCode = (aTypeSourceCode: string, sourceCode: string): result< + 'v, + ErrorValue.t, +> => { + let reducerFn = Expression.reduceExpression + let rResult = + Reducer.parse(sourceCode)->Belt.Result.flatMap(expr => + reducerFn(expr, Module.emptyBindings, InternalExpressionValue.defaultEnvironment) + ) + rResult->Belt.Result.flatMap(result => TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn)) +} + +let myTypeCheck = (aTypeSourceCode: string, sourceCode: string): string => + switch isTypeOfSourceCode(aTypeSourceCode, sourceCode) { + | Ok(_) => "Ok" + | Error(error) => ErrorValue.errorToString(error) + } + +let myTypeCheckExpectEqual = (aTypeSourceCode, sourceCode, answer) => + expect(myTypeCheck(aTypeSourceCode, sourceCode))->toEqual(answer) + +let _myTypeCheckTest = (test, aTypeSourceCode, sourceCode, answer) => + test(aTypeSourceCode, () => myTypeCheckExpectEqual(aTypeSourceCode, sourceCode, answer)) + +let myTypeCheckTest = (aTypeSourceCode, sourceCode, answer) => + _myTypeCheckTest(test, aTypeSourceCode, sourceCode, answer) +module MySkip = { + let myTypeCheckTest = (aTypeSourceCode, sourceCode, answer) => + _myTypeCheckTest(Skip.test, aTypeSourceCode, sourceCode, answer) +} +module MyOnly = { + let myTypeCheckTest = (aTypeSourceCode, sourceCode, answer) => + _myTypeCheckTest(Only.test, aTypeSourceCode, sourceCode, answer) +} + +myTypeCheckTest("number", "1", "Ok") +myTypeCheckTest("number", "'2'", "Expected type: number but got: '2'") +myTypeCheckTest("string", "3", "Expected type: string but got: 3") +myTypeCheckTest("string", "'a'", "Ok") +myTypeCheckTest("[number]", "[1,2,3]", "Ok") +myTypeCheckTest("[number]", "['a','a','a']", "Expected type: number but got: 'a'") +myTypeCheckTest("[number]", "[1,'a',3]", "Expected type: number but got: 'a'") +myTypeCheckTest("[number, string]", "[1,'a']", "Ok") +myTypeCheckTest("[number, string]", "[1, 2]", "Expected type: string but got: 2") +myTypeCheckTest( + "[number, string, string]", + "[1,'a']", + "Expected type: [number, string, string] but got: [1,'a']", +) +myTypeCheckTest( + "[number, string]", + "[1,'a', 3]", + "Expected type: [number, string] but got: [1,'a',3]", +) +myTypeCheckTest("{age: number, name: string}", "{age: 1, name: 'a'}", "Ok") +myTypeCheckTest( + "{age: number, name: string}", + "{age: 1, name: 'a', job: 'IT'}", + "Expected type: {age: number, name: string} but got: {age: 1,job: 'IT',name: 'a'}", +) +myTypeCheckTest("number | string", "1", "Ok") +myTypeCheckTest("date | string", "1", "Expected type: (date | string) but got: 1") +myTypeCheckTest("number<-min(10)", "10", "Ok") +myTypeCheckTest("number<-min(10)", "0", "Expected type: number<-min(10) but got: 0") 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 e0e6902e..397265ae 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 @@ -144,7 +144,7 @@ let dispatchMacroCall = ( let ifTrueBlock = eBlock(list{ifTrue}) ExpressionWithContext.withContext(ifTrueBlock, bindings)->Ok } - | _ => REExpectedType("Boolean")->Error + | _ => REExpectedType("Boolean", "")->Error } ) } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res index beaee7f7..211c9f53 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_ErrorValue.res @@ -7,7 +7,7 @@ type errorValue = | REArrayIndexNotFound(string, int) | REAssignmentExpected | REDistributionError(DistributionTypes.error) - | REExpectedType(string) + | REExpectedType(string, string) | REExpressionExpected | REFunctionExpected(string) | REFunctionNotFound(string) @@ -55,6 +55,6 @@ let errorToString = err => | RESymbolNotFound(symbolName) => `${symbolName} is not defined` | RESyntaxError(desc, _) => `Syntax Error: ${desc}` | RETodo(msg) => `TODO: ${msg}` - | REExpectedType(typeName) => `Expected type: ${typeName}` + | REExpectedType(typeName, valueString) => `Expected type: ${typeName} but got: ${valueString}` | REUnitNotFound(unitName) => `Unit not found: ${unitName}` } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Modifiers.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Modifiers.res new file mode 100644 index 00000000..457e97d8 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Modifiers.res @@ -0,0 +1,53 @@ +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module T = Reducer_Type_T + +let isMin = (modifierArg: InternalExpressionValue.t, aValue: InternalExpressionValue.t): bool => { + let pair = (modifierArg, aValue) + switch pair { + | (IEvNumber(a), IEvNumber(b)) => a <= b + | _ => false + } +} + +let isMax = (modifierArg: InternalExpressionValue.t, aValue: InternalExpressionValue.t): bool => { + let pair = (modifierArg, aValue) + switch pair { + | (IEvNumber(a), IEvNumber(b)) => a >= b + | _ => false + } +} + +let isMemberOf = ( + modifierArg: InternalExpressionValue.t, + aValue: InternalExpressionValue.t, +): bool => { + let pair = (modifierArg, aValue) + switch pair { + | (ievA, IEvArray(b)) => Js.Array2.includes(b, ievA) + | _ => false + } +} + +let checkModifier = ( + key: string, + modifierArg: InternalExpressionValue.t, + aValue: InternalExpressionValue.t, +): bool => + switch key { + | "min" => isMin(modifierArg, aValue) + | "max" => isMax(modifierArg, aValue) + | "isMemberOf" => isMemberOf(modifierArg, aValue) + | _ => false + } + +let checkModifiers = ( + modifiers: Belt.Map.String.t, + aValue: InternalExpressionValue.t, +): bool => { + modifiers->Belt.Map.String.reduce(true, (acc, key, modifierArg) => + switch acc { + | true => checkModifier(key, modifierArg, aValue) + | _ => acc + } + ) +} diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res index 0e3b240d..d8011d23 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res @@ -11,6 +11,7 @@ type rec iType = | ItTypeRecord({properties: Belt.Map.String.t}) type t = iType +type typeErrorValue = TypeMismatch(t, InternalExpressionValue.t) let rec toString = (t: t): string => { switch t { diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res index a1a6bdc2..2778d3e4 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res @@ -1,71 +1,168 @@ -// module ErrorValue = Reducer_ErrorValue +module ExpressionT = Reducer_Expression_T module InternalExpressionValue = ReducerInterface_InternalExpressionValue module T = Reducer_Type_T -// module TypeBuilder = Reducer_Type_TypeBuilder +module TypeModifiers = Reducer_Type_Modifiers open InternalExpressionValue -type typeErrorValue = TypeError(T.t, InternalExpressionValue.t) - -let rec isOfResolvedIType = (anIType: T.iType, aValue): result => { +let rec isITypeOf = (anIType: T.iType, aValue): result => { let caseTypeIdentifier = (anUpperTypeName, aValue) => { let aTypeName = anUpperTypeName->Js.String2.toLowerCase let valueTypeName = aValue->valueToValueType->valueTypeToString->Js.String2.toLowerCase - switch aTypeName === valueTypeName { + switch aTypeName == valueTypeName { | true => Ok(true) - | false => TypeError(anIType, aValue)->Error + | false => T.TypeMismatch(anIType, aValue)->Error } } - let _caseRecord = (anIType, evValue, propertyMap, map) => { - Belt.Map.String.reduce(propertyMap, Ok(true), (acc, property, propertyType) => { + let caseRecord = (anIType, propertyMap: Belt.Map.String.t, evValue) => + switch evValue { + | IEvRecord(aRecord) => + if ( + Js.Array2.length(propertyMap->Belt.Map.String.keysToArray) == + Js.Array2.length(aRecord->Belt.Map.String.keysToArray) + ) { + Belt.Map.String.reduce(propertyMap, Ok(true), (acc, property, propertyType) => { + Belt.Result.flatMap(acc, _ => + switch Belt.Map.String.get(aRecord, property) { + | Some(propertyValue) => isITypeOf(propertyType, propertyValue) + | None => T.TypeMismatch(anIType, evValue)->Error + } + ) + }) + } else { + T.TypeMismatch(anIType, evValue)->Error + } + + | _ => T.TypeMismatch(anIType, evValue)->Error + } + + let caseArray = (anIType, elementType, evValue) => + switch evValue { + | IEvArray(anArray) => + Belt.Array.reduce(anArray, Ok(true), (acc, element) => + Belt.Result.flatMap(acc, _ => + switch isITypeOf(elementType, element) { + | Ok(_) => Ok(true) + | Error(error) => error->Error + } + ) + ) + | _ => T.TypeMismatch(anIType, evValue)->Error + } + + let caseTuple = (anIType, elementTypes, evValue) => + switch evValue { + | IEvArray(anArray) => + if Js.Array2.length(elementTypes) == Js.Array2.length(anArray) { + let zipped = Belt.Array.zip(elementTypes, anArray) + Belt.Array.reduce(zipped, Ok(true), (acc, (elementType, element)) => + switch acc { + | Ok(_) => + switch isITypeOf(elementType, element) { + | Ok(_) => acc + | Error(error) => Error(error) + } + | _ => acc + } + ) + } else { + T.TypeMismatch(anIType, evValue)->Error + } + | _ => T.TypeMismatch(anIType, evValue)->Error + } + + let caseOr = (anIType, anITypeArray, evValue) => + switch Belt.Array.reduce(anITypeArray, Ok(false), (acc, anIType) => Belt.Result.flatMap(acc, _ => - switch Belt.Map.String.get(map, property) { - | Some(propertyValue) => isOfResolvedIType(propertyType, propertyValue) - | None => TypeError(anIType, evValue)->Error + switch acc { + | Ok(false) => + switch isITypeOf(anIType, evValue) { + | Ok(_) => Ok(true) + | Error(_) => acc + } + | _ => acc } ) - }) - } - let _caseArray = (anIType, evValue, elementType, anArray) => { - Belt.Array.reduceWithIndex(anArray, Ok(true), (acc, element, _index) => { - switch isOfResolvedIType(elementType, element) { - | Ok(_) => acc - | Error(_) => TypeError(anIType, evValue)->Error + ) { + | Ok(true) => Ok(true) + | Ok(false) => T.TypeMismatch(anIType, evValue)->Error + | Error(error) => Error(error) + } + + let caseModifiedType = ( + anIType: T.iType, + modifiedType: T.iType, + modifiers: Belt.Map.String.t, + aValue: InternalExpressionValue.t, + ) => { + isITypeOf(modifiedType, aValue)->Belt.Result.flatMap(_result => { + if TypeModifiers.checkModifiers(modifiers, aValue) { + Ok(true) + } else { + T.TypeMismatch(anIType, aValue)->Error } }) } switch anIType { | ItTypeIdentifier(name) => caseTypeIdentifier(name, aValue) - // TODO: Work in progress. Code is commented to make an a release of other features - // | ItModifiedType({modifiedType: anIType}) => raise(Reducer_Exception.ImpossibleException) - // | ItTypeOr({typeOr: anITypeArray}) => raise(Reducer_Exception.ImpossibleException) - // | ItTypeFunction({inputs: anITypeArray, output: anIType}) => - // raise(Reducer_Exception.ImpossibleException) - // | ItTypeArray({element: anIType}) => raise(Reducer_Exception.ImpossibleException) - // | ItTypeTuple({elements: anITypeArray}) => raise(Reducer_Exception.ImpossibleException) - // | ItTypeRecord({properties: anITypeMap}) => raise(Reducer_Exception.ImpossibleException) - | _ => raise(Reducer_Exception.ImpossibleException("Reducer_TypeChecker-isOfResolvedIType")) + | ItModifiedType({modifiedType, modifiers}) => + caseModifiedType(anIType, modifiedType, modifiers, aValue) //{modifiedType: iType, modifiers: Belt.Map.String.t} + | ItTypeOr({typeOr}) => caseOr(anIType, typeOr, aValue) + | ItTypeFunction(_) => + raise( + Reducer_Exception.ImpossibleException( + "Reducer_TypeChecker-functions are without a type at the moment", + ), + ) + | ItTypeArray({element}) => caseArray(anIType, element, aValue) + | ItTypeTuple({elements}) => caseTuple(anIType, elements, aValue) + | ItTypeRecord({properties}) => caseRecord(anIType, properties, aValue) } } -// let isOfResolvedType = (aType: InternalExpressionValue.t, aValue): result => -// aType->T.fromIEvValue->isOfResolvedIType(aValue) +let isTypeOf = ( + typeExpressionSourceCode: string, + aValue: InternalExpressionValue.t, + reducerFn: ExpressionT.reducerFn, +): result => { + switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) { + | Ok(anIType) => + switch isITypeOf(anIType, aValue) { + | Ok(_) => Ok(aValue) + | Error(T.TypeMismatch(anIType, evValue)) => + Error( + ErrorValue.REExpectedType(anIType->T.toString, evValue->InternalExpressionValue.toString), + ) + } + | Error(error) => Error(error) // Directly propagating - err => err - causes type mismatch + } +} -// TODO: Work in progress. Code is commented to make an a release of other features -// let checkArguments = ( -// evFunctionType: InternalExpressionValue.t, -// args: array, -// ) => { -// let functionType = switch evFunctionType { -// | IEvRecord(functionType) => functionType -// | _ => raise(Reducer_Exception.ImpossibleException) -// } -// let evInputs = functionType->Belt.Map.String.getWithDefault("inputs", []->IEvArray) -// let inputs = switch evInputs { -// | IEvArray(inputs) => inputs -// | _ => raise(Reducer_Exception.ImpossibleException) -// } -// let rTupleType = TypeBuilder.typeTuple(inputs) -// Belt.Result.flatMap(rTupleType, tupleType => isOfResolvedType(tupleType, args->IEvArray)) -// } +let checkITypeArguments = (anIType: T.iType, args: array): result< + bool, + T.typeErrorValue, +> => { + switch anIType { + | T.ItTypeFunction({inputs}) => isITypeOf(T.ItTypeTuple({elements: inputs}), args->IEvArray) + | _ => T.TypeMismatch(anIType, args->IEvArray)->Error + } +} + +let checkArguments = ( + typeExpressionSourceCode: string, + args: array, + reducerFn: ExpressionT.reducerFn, +): result => { + switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) { + | Ok(anIType) => + switch checkITypeArguments(anIType, args) { + | Ok(_) => Ok(args->IEvArray) + | Error(T.TypeMismatch(anIType, evValue)) => + Error( + ErrorValue.REExpectedType(anIType->T.toString, evValue->InternalExpressionValue.toString), + ) + } + | Error(error) => Error(error) // Directly propagating - err => err - causes type mismatch + } +} From 6966c8d3e51ef8fac1b9870ede6aec561baaf7dc Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 18 Jul 2022 15:17:41 +0200 Subject: [PATCH 23/40] ternary validation --- .../__tests__/Reducer/Reducer_ternaryOperator_test.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res index 25353e89..22fa8328 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_ternaryOperator_test.res @@ -10,5 +10,5 @@ describe("Evaluate ternary operator", () => { testEvalToBe("false ? 'YES' : 'NO'", "Ok('NO')") testEvalToBe("2 > 1 ? 'YES' : 'NO'", "Ok('YES')") testEvalToBe("2 <= 1 ? 'YES' : 'NO'", "Ok('NO')") - testEvalToBe("1+1 ? 'YES' : 'NO'", "Error(Expected type: Boolean)") + testEvalToBe("1+1 ? 'YES' : 'NO'", "Error(Expected type: Boolean but got: )") }) From 628b1055352a7b0ef2d38710640600a0d2a4b5a1 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 18 Jul 2022 08:24:11 -0700 Subject: [PATCH 24/40] PointSet -> Pointset --- .../FunctionRegistry_Core.res | 2 +- .../FunctionRegistry/Library/FR_Pointset.res | 20 ++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 85cf5609..7ac42686 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -333,7 +333,7 @@ module FnDefinition = { let isMatch = (t: t, args: array) => { let argValues = FRType.matchWithExpressionValueArray(t.inputs, args) switch argValues { - | Some(values) => true + | Some(_) => true | None => false } } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res index 9a0745c1..dc4daead 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/Library/FR_Pointset.res @@ -1,7 +1,7 @@ open FunctionRegistry_Core open FunctionRegistry_Helpers -let nameSpace = "PointSet" +let nameSpace = "Pointset" let requiresNamespace = true let inputsTodist = (inputs: array, makeDist) => { @@ -28,6 +28,15 @@ let library = [ ~name="makeContinuous", ~nameSpace, ~requiresNamespace, + ~examples=[ + `Pointset.makeContinuous([ + {x: 0, y: 0.2}, + {x: 1, y: 0.7}, + {x: 2, y: 0.8}, + {x: 3, y: 0.2} + ])`, + ], + ~output=ReducerInterface_InternalExpressionValue.EvtDistribution, ~definitions=[ FnDefinition.make( ~name="makeContinuous", @@ -42,6 +51,15 @@ let library = [ ~name="makeDiscrete", ~nameSpace, ~requiresNamespace, + ~examples=[ + `Pointset.makeDiscrete([ + {x: 0, y: 0.2}, + {x: 1, y: 0.7}, + {x: 2, y: 0.8}, + {x: 3, y: 0.2} + ])`, + ], + ~output=ReducerInterface_InternalExpressionValue.EvtDistribution, ~definitions=[ FnDefinition.make( ~name="makeDiscrete", From 8f742bf99f011f1cac69d8a38652b5c224b1cdde Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 18 Jul 2022 08:47:02 -0700 Subject: [PATCH 25/40] Quick fix for component --- packages/components/src/components/FunctionChart1Dist.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/components/src/components/FunctionChart1Dist.tsx b/packages/components/src/components/FunctionChart1Dist.tsx index 650d2753..f8d072d7 100644 --- a/packages/components/src/components/FunctionChart1Dist.tsx +++ b/packages/components/src/components/FunctionChart1Dist.tsx @@ -88,7 +88,7 @@ let getPercentiles = ({ chartSettings, fn, environment }) => { let chartPointsData: point[] = chartPointsToRender.map((x) => { let result = runForeign(fn, [x], environment); if (result.tag === "Ok") { - if (result.value.tag == "distribution") { + if (result.value.tag === "distribution") { return { x, value: { tag: "Ok", value: result.value.value } }; } else { return { @@ -165,12 +165,14 @@ export const FunctionChart1Dist: React.FC = ({ setMouseOverlay(NaN); } const signalListeners = { mousemove: handleHover, mouseout: handleOut }; + + //TODO: This custom error handling is a bit hacky and should be improved. let mouseItem: result = !!mouseOverlay ? runForeign(fn, [mouseOverlay], environment) : { tag: "Error", value: { - tag: "REExpectedType", + tag: "RETodo", value: "Hover x-coordinate returned NaN. Expected a number.", }, }; From c1429e09078a8669b34ce55b61f94490d2fc1a29 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 18 Jul 2022 18:16:49 +0200 Subject: [PATCH 26/40] simplified modules --- .../Reducer_Peggy_ToExpression_test.res | 1 - .../Reducer_Type/Reducer_Type_Compile_test.res | 2 +- .../Reducer_Type_TypeChecker_arguments_test.res | 4 ++-- .../Reducer_Type/Reducer_Type_TypeChecker_test.res | 4 ++-- .../Reducer/Reducer_Bindings/Reducer_Bindings.res | 3 +++ .../Reducer/Reducer_Type/Reducer_Type_Compile.res | 12 ++++++++---- .../ReducerInterface_InternalExpressionValue.res | 2 +- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res index 74bf59e0..b8a81f25 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res @@ -3,7 +3,6 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue open Jest open Reducer_Peggy_TestHelpers -open Expect describe("Peggy to Expression", () => { describe("literals operators parenthesis", () => { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res index 3f97ca3f..4de688d1 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res @@ -1,6 +1,6 @@ module Expression = Reducer_Expression module InternalExpressionValue = ReducerInterface_InternalExpressionValue -module Module = Reducer_Module +module Bindings = Reducer_Bindings module T = Reducer_Type_T module TypeCompile = Reducer_Type_Compile diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res index 4f490bd5..9c23e38e 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res @@ -2,7 +2,7 @@ module Expression = Reducer_Expression module ExpressionT = Reducer_Expression_T module ErrorValue = Reducer_ErrorValue module InternalExpressionValue = ReducerInterface_InternalExpressionValue -module Module = Reducer_Module +module Bindings = Reducer_Bindings module T = Reducer_Type_T module TypeChecker = Reducer_Type_TypeChecker @@ -16,7 +16,7 @@ let checkArgumentsSourceCode = (aTypeSourceCode: string, sourceCode: string): re let reducerFn = Expression.reduceExpression let rResult = Reducer.parse(sourceCode)->Belt.Result.flatMap(expr => - reducerFn(expr, Module.emptyBindings, InternalExpressionValue.defaultEnvironment) + reducerFn(expr, Bindings.emptyBindings, InternalExpressionValue.defaultEnvironment) ) rResult->Belt.Result.flatMap(result => switch result { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res index 5b093060..d845d550 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res @@ -2,7 +2,7 @@ module Expression = Reducer_Expression module ExpressionT = Reducer_Expression_T module ErrorValue = Reducer_ErrorValue module InternalExpressionValue = ReducerInterface_InternalExpressionValue -module Module = Reducer_Module +module Bindings = Reducer_Bindings module T = Reducer_Type_T module TypeChecker = Reducer_Type_TypeChecker @@ -19,7 +19,7 @@ let isTypeOfSourceCode = (aTypeSourceCode: string, sourceCode: string): result< let reducerFn = Expression.reduceExpression let rResult = Reducer.parse(sourceCode)->Belt.Result.flatMap(expr => - reducerFn(expr, Module.emptyBindings, InternalExpressionValue.defaultEnvironment) + reducerFn(expr, Bindings.emptyBindings, InternalExpressionValue.defaultEnvironment) ) rResult->Belt.Result.flatMap(result => TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn)) } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res index f02cd54f..28175d7a 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res @@ -1,3 +1,6 @@ +// Only Bindings as the global module is supported +// Other module operations such as import export will be prepreocessed jobs + module ExpressionT = Reducer_Expression_T module InternalExpressionValue = ReducerInterface_InternalExpressionValue open Reducer_ErrorValue diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res index c7a776b7..2119ee62 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Compile.res @@ -1,7 +1,7 @@ module ErrorValue = Reducer_ErrorValue module ExpressionT = Reducer_Expression_T module InternalExpressionValue = ReducerInterface_InternalExpressionValue -module Module = Reducer_Module +module Bindings = Reducer_Bindings module T = Reducer_Type_T let ievFromTypeExpression = ( @@ -11,11 +11,15 @@ let ievFromTypeExpression = ( let sIndex = "compiled" let sourceCode = `type ${sIndex}=${typeExpressionSourceCode}` Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr => { - let rContext = reducerFn(expr, Module.emptyBindings, InternalExpressionValue.defaultEnvironment) + let rContext = reducerFn( + expr, + Bindings.emptyBindings, + InternalExpressionValue.defaultEnvironment, + ) Belt.Result.map(rContext, context => switch context { - | IEvModule(nameSpace) => - switch Module.getType(nameSpace, sIndex) { + | IEvBindings(nameSpace) => + switch Bindings.getType(nameSpace, sIndex) { | Some(value) => value | None => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-none")) } diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res index 06ab2376..4523b02a 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_InternalExpressionValue.res @@ -84,7 +84,7 @@ let toStringWithType = aValue => | IEvDeclaration(_) => `Declaration::${toString(aValue)}` | IEvDistribution(_) => `Distribution::${toString(aValue)}` | IEvLambda(_) => `Lambda::${toString(aValue)}` - | IEvBindings(_) => `Module::${toString(aValue)}` + | IEvBindings(_) => `Bindings::${toString(aValue)}` | IEvNumber(_) => `Number::${toString(aValue)}` | IEvRecord(_) => `Record::${toString(aValue)}` | IEvString(_) => `String::${toString(aValue)}` From 15d63a6a962545790e9e45490d097f319b760760 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 18 Jul 2022 18:31:09 +0200 Subject: [PATCH 27/40] type modifiers -> type contracts --- .../Reducer_Peggy/Reducer_Peggy_Parse_type_test.res | 6 +++--- .../Reducer_Peggy_ToExpression_type_test.res | 6 +++--- ...Type_Modifiers.res => Reducer_Type_Contracts.res} | 4 ++-- .../rescript/Reducer/Reducer_Type/Reducer_Type_T.res | 12 ++++++------ .../Reducer_Type/Reducer_Type_TypeChecker.res | 10 +++++----- 5 files changed, 19 insertions(+), 19 deletions(-) rename packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/{Reducer_Type_Modifiers.res => Reducer_Type_Contracts.res} (90%) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res index f1dcd4bc..4f7dabdc 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res @@ -20,7 +20,7 @@ describe("Peggy parse type", () => { "{(::$_typeOf_$ :f (::$_typeFunction_$ (::$_constructArray_$ (#number #number #number))))}", ) }) - describe("high priority modifier", () => { + describe("high priority contract", () => { testParse( "answer: number<-min<-max(100)|string", "{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ ((::$_typeModifier_max_$ (::$_typeModifier_min_$ #number) 100) #string))))}", @@ -30,7 +30,7 @@ describe("Peggy parse type", () => { "{(::$_typeOf_$ :answer (::$_typeModifier_memberOf_$ #number (::$_constructArray_$ (1 3 5))))}", ) }) - describe("low priority modifier", () => { + describe("low priority contract", () => { testParse( "answer: number | string $ opaque", "{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}", @@ -70,7 +70,7 @@ describe("Peggy parse type", () => { "{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}", ) }) - describe("squiggle expressions in type modifiers", () => { + describe("squiggle expressions in type contracts", () => { testParse( "odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))", "{:odds1 = {(::$_constructArray_$ (1 3 5))}; :odds2 = {(::$_constructArray_$ (7 9))}; (::$_typeAlias_$ #odds (::$_typeModifier_memberOf_$ #number (::concat :odds1 :odds2)))}", diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res index 12d2d62b..9849adb0 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res @@ -40,7 +40,7 @@ describe("Peggy Types to Expression", () => { (), ) }) - describe("high priority modifier", () => { + describe("high priority contract", () => { testToExpression( "answer: number<-min(1)<-max(100)|string", "{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ ((:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 100) #string))))}", @@ -78,7 +78,7 @@ describe("Peggy Types to Expression", () => { (), ) }) - describe("low priority modifier", () => { + describe("low priority contract", () => { testToExpression( "answer: number | string $ opaque", "{(:$_typeOf_$ :answer (:$_typeModifier_opaque_$ (:$_typeOr_$ (:$_constructArray_$ (#number #string)))))}", @@ -86,7 +86,7 @@ describe("Peggy Types to Expression", () => { (), ) }) - describe("squiggle expressions in type modifiers", () => { + describe("squiggle expressions in type contracts", () => { testToExpression( "odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))", "{(:$_let_$ :odds1 {(:$_constructArray_$ (1 3 5))}); (:$_let_$ :odds2 {(:$_constructArray_$ (7 9))}); (:$_typeAlias_$ #odds (:$_typeModifier_memberOf_$ #number (:concat :odds1 :odds2)))}", diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Modifiers.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Contracts.res similarity index 90% rename from packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Modifiers.res rename to packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Contracts.res index 457e97d8..7b68f178 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Modifiers.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_Contracts.res @@ -41,10 +41,10 @@ let checkModifier = ( } let checkModifiers = ( - modifiers: Belt.Map.String.t, + contracts: Belt.Map.String.t, aValue: InternalExpressionValue.t, ): bool => { - modifiers->Belt.Map.String.reduce(true, (acc, key, modifierArg) => + contracts->Belt.Map.String.reduce(true, (acc, key, modifierArg) => switch acc { | true => checkModifier(key, modifierArg, aValue) | _ => acc diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res index d8011d23..511fe815 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_T.res @@ -3,7 +3,7 @@ open InternalExpressionValue type rec iType = | ItTypeIdentifier(string) - | ItModifiedType({modifiedType: iType, modifiers: Belt.Map.String.t}) + | ItModifiedType({modifiedType: iType, contracts: Belt.Map.String.t}) | ItTypeOr({typeOr: array}) | ItTypeFunction({inputs: array, output: iType}) | ItTypeArray({element: iType}) @@ -16,8 +16,8 @@ type typeErrorValue = TypeMismatch(t, InternalExpressionValue.t) let rec toString = (t: t): string => { switch t { | ItTypeIdentifier(s) => s - | ItModifiedType({modifiedType, modifiers}) => - `${toString(modifiedType)}${modifiers->Belt.Map.String.reduce("", (acc, k, v) => + | ItModifiedType({modifiedType, contracts}) => + `${toString(modifiedType)}${contracts->Belt.Map.String.reduce("", (acc, k, v) => Js.String2.concatMany(acc, ["<-", k, "(", InternalExpressionValue.toString(v), ")"]) )}` | ItTypeOr({typeOr}) => `(${Js.Array2.map(typeOr, toString)->Js.Array2.joinWith(" | ")})` @@ -82,7 +82,7 @@ let rec fromTypeMap = typeMap => { default, ) - let modifiers = + let contracts = typeMap->Belt.Map.String.keep((k, _v) => ["min", "max", "memberOf"]->Js.Array2.includes(k)) let makeIt = switch evTypeTag { @@ -96,9 +96,9 @@ let rec fromTypeMap = typeMap => { | _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_T-evTypeTag")) } - Belt.Map.String.isEmpty(modifiers) + Belt.Map.String.isEmpty(contracts) ? makeIt - : ItModifiedType({modifiedType: makeIt, modifiers: modifiers}) + : ItModifiedType({modifiedType: makeIt, contracts: contracts}) } and fromIEvValue = (ievValue: InternalExpressionValue.t): iType => diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res index 2778d3e4..e4336df5 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Type/Reducer_Type_TypeChecker.res @@ -1,7 +1,7 @@ module ExpressionT = Reducer_Expression_T module InternalExpressionValue = ReducerInterface_InternalExpressionValue module T = Reducer_Type_T -module TypeModifiers = Reducer_Type_Modifiers +module TypeContracts = Reducer_Type_Contracts open InternalExpressionValue let rec isITypeOf = (anIType: T.iType, aValue): result => { @@ -92,11 +92,11 @@ let rec isITypeOf = (anIType: T.iType, aValue): result = let caseModifiedType = ( anIType: T.iType, modifiedType: T.iType, - modifiers: Belt.Map.String.t, + contracts: Belt.Map.String.t, aValue: InternalExpressionValue.t, ) => { isITypeOf(modifiedType, aValue)->Belt.Result.flatMap(_result => { - if TypeModifiers.checkModifiers(modifiers, aValue) { + if TypeContracts.checkModifiers(contracts, aValue) { Ok(true) } else { T.TypeMismatch(anIType, aValue)->Error @@ -106,8 +106,8 @@ let rec isITypeOf = (anIType: T.iType, aValue): result = switch anIType { | ItTypeIdentifier(name) => caseTypeIdentifier(name, aValue) - | ItModifiedType({modifiedType, modifiers}) => - caseModifiedType(anIType, modifiedType, modifiers, aValue) //{modifiedType: iType, modifiers: Belt.Map.String.t} + | ItModifiedType({modifiedType, contracts}) => + caseModifiedType(anIType, modifiedType, contracts, aValue) //{modifiedType: iType, contracts: Belt.Map.String.t} | ItTypeOr({typeOr}) => caseOr(anIType, typeOr, aValue) | ItTypeFunction(_) => raise( From 6e1be862d2bcf1dd685ff830a52eab192832003b Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 18 Jul 2022 18:51:05 +0200 Subject: [PATCH 28/40] reducer passed to external library --- .../Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res | 3 +-- .../ReducerInterface/ReducerInterface_ExternalLibrary.res | 4 ++-- 2 files changed, 3 insertions(+), 4 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 d0d88b2a..aa27d7ec 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 @@ -255,11 +255,10 @@ let dispatch = (call: functionCall, environment, reducer: ExpressionT.reducerFn) 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, callInternalWithReducer) + ExternalLibrary.dispatch((Js.String.make(fn), args), environment, reducer, 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/ReducerInterface/ReducerInterface_ExternalLibrary.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res index 3e6172c9..2a479bb5 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res @@ -23,7 +23,7 @@ let tryRegistry = ((fnName, args): InternalExpressionValue.functionCall, env) => ) } -let dispatch = (call: InternalExpressionValue.functionCall, environment, chain): result< +let dispatch = (call: InternalExpressionValue.functionCall, environment, reducer, chain): result< internalExpressionValue, 'e, > => { @@ -33,7 +33,7 @@ let dispatch = (call: InternalExpressionValue.functionCall, environment, chain): () => ReducerInterface_Duration.dispatch(call, environment), () => ReducerInterface_Number.dispatch(call, environment), () => tryRegistry(call, environment), - ])->E.O2.default(chain(call, environment)) + ])->E.O2.default(chain(call, environment, reducer)) } /* If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally. From 4535041876760f18bd80ef46f3832390cbd2c889 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Mon, 18 Jul 2022 22:52:19 +0200 Subject: [PATCH 29/40] less test clutter --- .../Reducer_Type_Compile_test.res | 36 ++++++--------- ...educer_Type_TypeChecker_arguments_test.res | 15 +------ .../Reducer_Type_TypeChecker_test.res | 44 ++++++++----------- 3 files changed, 33 insertions(+), 62 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res index 4de688d1..71f90373 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_Compile_test.res @@ -15,7 +15,7 @@ let myIevEvalToString = (aTypeSourceCode: string) => let myIevExpectEqual = (aTypeSourceCode, answer) => expect(myIevEvalToString(aTypeSourceCode))->toEqual(answer) -let _myIevTest = (test, aTypeSourceCode, answer) => +let myIevTest = (test, aTypeSourceCode, answer) => test(aTypeSourceCode, () => myIevExpectEqual(aTypeSourceCode, answer)) let myTypeEval = (aTypeSourceCode: string) => @@ -25,38 +25,28 @@ let myTypeEvalToString = (aTypeSourceCode: string) => myTypeEval(aTypeSourceCode let myTypeExpectEqual = (aTypeSourceCode, answer) => expect(myTypeEvalToString(aTypeSourceCode))->toEqual(answer) -let _myTypeTest = (test, aTypeSourceCode, answer) => +let myTypeTest = (test, aTypeSourceCode, answer) => test(aTypeSourceCode, () => myTypeExpectEqual(aTypeSourceCode, answer)) -let myIevTest = (aTypeSourceCode, answer) => _myIevTest(test, aTypeSourceCode, answer) -let myTypeTest = (aTypeSourceCode, answer) => _myTypeTest(test, aTypeSourceCode, answer) -module MySkip = { - let myIevTest = (aTypeSourceCode, answer) => _myIevTest(Skip.test, aTypeSourceCode, answer) - let myTypeTest = (aTypeSourceCode, answer) => _myTypeTest(Skip.test, aTypeSourceCode, answer) -} -module MyOnly = { - let myIevTest = (aTypeSourceCode, answer) => _myIevTest(Only.test, aTypeSourceCode, answer) - let myTypeTest = (aTypeSourceCode, answer) => _myTypeTest(Only.test, aTypeSourceCode, answer) -} - // | ItTypeIdentifier(string) -myTypeTest("number", "number") -myTypeTest("(number)", "number") +myTypeTest(test, "number", "number") +myTypeTest(test, "(number)", "number") // | ItModifiedType({modifiedType: iType}) -myIevTest("number<-min(0)", "Ok({min: 0,typeIdentifier: #number,typeTag: 'typeIdentifier'})") -myTypeTest("number<-min(0)", "number<-min(0)") +myIevTest(test, "number<-min(0)", "Ok({min: 0,typeIdentifier: #number,typeTag: 'typeIdentifier'})") +myTypeTest(test, "number<-min(0)", "number<-min(0)") // | ItTypeOr({typeOr: array}) -myTypeTest("number | string", "(number | string)") +myTypeTest(test, "number | string", "(number | string)") // | ItTypeFunction({inputs: array, output: iType}) -myTypeTest("number => number => number", "(number => number => number)") +myTypeTest(test, "number => number => number", "(number => number => number)") // | ItTypeArray({element: iType}) -myIevTest("[number]", "Ok({element: #number,typeTag: 'typeArray'})") -myTypeTest("[number]", "[number]") +myIevTest(test, "[number]", "Ok({element: #number,typeTag: 'typeArray'})") +myTypeTest(test, "[number]", "[number]") // | ItTypeTuple({elements: array}) -myTypeTest("[number, string]", "[number, string]") +myTypeTest(test, "[number, string]", "[number, string]") // | ItTypeRecord({properties: Belt.Map.String.t}) myIevTest( + test, "{age: number, name: string}", "Ok({properties: {age: #number,name: #string},typeTag: 'typeRecord'})", ) -myTypeTest("{age: number, name: string}", "{age: number, name: string}") +myTypeTest(test, "{age: number, name: string}", "{age: number, name: string}") diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res index 9c23e38e..07da15bb 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_arguments_test.res @@ -35,18 +35,7 @@ let myCheckArguments = (aTypeSourceCode: string, sourceCode: string): string => let myCheckArgumentsExpectEqual = (aTypeSourceCode, sourceCode, answer) => expect(myCheckArguments(aTypeSourceCode, sourceCode))->toEqual(answer) -let _myCheckArgumentsTest = (test, aTypeSourceCode, sourceCode, answer) => +let myCheckArgumentsTest = (test, aTypeSourceCode, sourceCode, answer) => test(aTypeSourceCode, () => myCheckArgumentsExpectEqual(aTypeSourceCode, sourceCode, answer)) -let myCheckArgumentsTest = (aTypeSourceCode, sourceCode, answer) => - _myCheckArgumentsTest(test, aTypeSourceCode, sourceCode, answer) -module MySkip = { - let myCheckArgumentsTest = (aTypeSourceCode, sourceCode, answer) => - _myCheckArgumentsTest(Skip.test, aTypeSourceCode, sourceCode, answer) -} -module MyOnly = { - let myCheckArgumentsTest = (aTypeSourceCode, sourceCode, answer) => - _myCheckArgumentsTest(Only.test, aTypeSourceCode, sourceCode, answer) -} - -myCheckArgumentsTest("number=>number=>number", "[1,2]", "Ok") +myCheckArgumentsTest(test, "number=>number=>number", "[1,2]", "Ok") diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res index d845d550..efd9bb18 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Type/Reducer_Type_TypeChecker_test.res @@ -33,46 +33,38 @@ let myTypeCheck = (aTypeSourceCode: string, sourceCode: string): string => let myTypeCheckExpectEqual = (aTypeSourceCode, sourceCode, answer) => expect(myTypeCheck(aTypeSourceCode, sourceCode))->toEqual(answer) -let _myTypeCheckTest = (test, aTypeSourceCode, sourceCode, answer) => +let myTypeCheckTest = (test, aTypeSourceCode, sourceCode, answer) => test(aTypeSourceCode, () => myTypeCheckExpectEqual(aTypeSourceCode, sourceCode, answer)) -let myTypeCheckTest = (aTypeSourceCode, sourceCode, answer) => - _myTypeCheckTest(test, aTypeSourceCode, sourceCode, answer) -module MySkip = { - let myTypeCheckTest = (aTypeSourceCode, sourceCode, answer) => - _myTypeCheckTest(Skip.test, aTypeSourceCode, sourceCode, answer) -} -module MyOnly = { - let myTypeCheckTest = (aTypeSourceCode, sourceCode, answer) => - _myTypeCheckTest(Only.test, aTypeSourceCode, sourceCode, answer) -} - -myTypeCheckTest("number", "1", "Ok") -myTypeCheckTest("number", "'2'", "Expected type: number but got: '2'") -myTypeCheckTest("string", "3", "Expected type: string but got: 3") -myTypeCheckTest("string", "'a'", "Ok") -myTypeCheckTest("[number]", "[1,2,3]", "Ok") -myTypeCheckTest("[number]", "['a','a','a']", "Expected type: number but got: 'a'") -myTypeCheckTest("[number]", "[1,'a',3]", "Expected type: number but got: 'a'") -myTypeCheckTest("[number, string]", "[1,'a']", "Ok") -myTypeCheckTest("[number, string]", "[1, 2]", "Expected type: string but got: 2") +myTypeCheckTest(test, "number", "1", "Ok") +myTypeCheckTest(test, "number", "'2'", "Expected type: number but got: '2'") +myTypeCheckTest(test, "string", "3", "Expected type: string but got: 3") +myTypeCheckTest(test, "string", "'a'", "Ok") +myTypeCheckTest(test, "[number]", "[1,2,3]", "Ok") +myTypeCheckTest(test, "[number]", "['a','a','a']", "Expected type: number but got: 'a'") +myTypeCheckTest(test, "[number]", "[1,'a',3]", "Expected type: number but got: 'a'") +myTypeCheckTest(test, "[number, string]", "[1,'a']", "Ok") +myTypeCheckTest(test, "[number, string]", "[1, 2]", "Expected type: string but got: 2") myTypeCheckTest( + test, "[number, string, string]", "[1,'a']", "Expected type: [number, string, string] but got: [1,'a']", ) myTypeCheckTest( + test, "[number, string]", "[1,'a', 3]", "Expected type: [number, string] but got: [1,'a',3]", ) -myTypeCheckTest("{age: number, name: string}", "{age: 1, name: 'a'}", "Ok") +myTypeCheckTest(test, "{age: number, name: string}", "{age: 1, name: 'a'}", "Ok") myTypeCheckTest( + test, "{age: number, name: string}", "{age: 1, name: 'a', job: 'IT'}", "Expected type: {age: number, name: string} but got: {age: 1,job: 'IT',name: 'a'}", ) -myTypeCheckTest("number | string", "1", "Ok") -myTypeCheckTest("date | string", "1", "Expected type: (date | string) but got: 1") -myTypeCheckTest("number<-min(10)", "10", "Ok") -myTypeCheckTest("number<-min(10)", "0", "Expected type: number<-min(10) but got: 0") +myTypeCheckTest(test, "number | string", "1", "Ok") +myTypeCheckTest(test, "date | string", "1", "Expected type: (date | string) but got: 1") +myTypeCheckTest(test, "number<-min(10)", "10", "Ok") +myTypeCheckTest(test, "number<-min(10)", "0", "Expected type: number<-min(10) but got: 0") From 30f721eeb613392459413a143b6dec7e507c330d Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 18 Jul 2022 16:10:19 -0700 Subject: [PATCH 30/40] Simple conversion away from using modules --- .../src/components/SquigglePlayground.tsx | 1 - .../__tests__/FunctionRegistry_test.res | 74 ++++++++--------- .../FunctionRegistry_Core.res | 83 ++++++++----------- .../ReducerInterface_StdLib.res | 1 - 4 files changed, 73 insertions(+), 86 deletions(-) diff --git a/packages/components/src/components/SquigglePlayground.tsx b/packages/components/src/components/SquigglePlayground.tsx index a8f5852a..3b901809 100644 --- a/packages/components/src/components/SquigglePlayground.tsx +++ b/packages/components/src/components/SquigglePlayground.tsx @@ -529,7 +529,6 @@ export const SquigglePlayground: FC = ({ const withoutEditor =
{tabs}
; - console.log(vars); return ( diff --git a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res index d68d9b01..6ee66f60 100644 --- a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res +++ b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res @@ -1,7 +1,7 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue module ExpressionT = Reducer_Expression_T -module Module = Reducer_Module -module Bindings = Reducer_Module +// module Module = Reducer_Module +// module Bindings = Reducer_Module module ErrorValue = Reducer_ErrorValue open Jest @@ -49,45 +49,45 @@ module FooImplementation = { let library = [fn1] } + +// let makeBindings = FunctionRegistry_Core.Registry.makeBindings(_, FooImplementation.library) -let makeBindings = FunctionRegistry_Core.Registry.makeBindings(_, FooImplementation.library) +// let stdLibWithFoo = Bindings.emptyBindings->makeBindings -let stdLibWithFoo = Bindings.emptyBindings->makeBindings +// let evalWithFoo = sourceCode => +// Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr => +// Reducer_Expression.reduceExpression( +// expr, +// stdLibWithFoo, +// InternalExpressionValue.defaultEnvironment, +// ) +// ) -let evalWithFoo = sourceCode => - Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr => - Reducer_Expression.reduceExpression( - expr, - stdLibWithFoo, - InternalExpressionValue.defaultEnvironment, - ) - ) +// let evalToStringResultWithFoo = sourceCode => +// evalWithFoo(sourceCode)->InternalExpressionValue.toStringResult -let evalToStringResultWithFoo = sourceCode => - evalWithFoo(sourceCode)->InternalExpressionValue.toStringResult +// describe("Module", () => { +// test("add2(1,2)", () => { +// let result = evalToStringResultWithFoo("Foo.add2(1,2)") +// expect(result)->toEqual("Ok(3)") +// }) +// test("add3(1,2,3)", () => { +// let result = evalToStringResultWithFoo("Foo.add3(1,2,3)") +// expect(result)->toEqual("Ok(6)") +// }) +// }) -describe("Module", () => { - test("add2(1,2)", () => { - let result = evalToStringResultWithFoo("Foo.add2(1,2)") - expect(result)->toEqual("Ok(3)") - }) - test("add3(1,2,3)", () => { - let result = evalToStringResultWithFoo("Foo.add3(1,2,3)") - expect(result)->toEqual("Ok(6)") - }) -}) +// describe("Fn auto-testing", () => { +// let items = FooImplementation.fn1.examples->E.A.to_list -describe("Fn auto-testing", () => { - let items = FooImplementation.fn1.examples->E.A.to_list +// testAll("tests of validity", items, r => { +// expect(r->evalWithFoo->E.R.isOk)->toEqual(true) +// }) - testAll("tests of validity", items, r => { - expect(r->evalWithFoo->E.R.isOk)->toEqual(true) - }) - - testAll("tests of type", items, r => { - let responseType = - r->evalWithFoo->E.R2.fmap(ReducerInterface_InternalExpressionValue.valueToValueType) - let expectedOutputType = FooImplementation.fn1.output |> E.O.toExn("") - expect(responseType)->toEqual(Ok(expectedOutputType)) - }) -}) +// testAll("tests of type", items, r => { +// let responseType = +// r->evalWithFoo->E.R2.fmap(ReducerInterface_InternalExpressionValue.valueToValueType) +// let expectedOutputType = FooImplementation.fn1.output |> E.O.toExn("") +// expect(responseType)->toEqual(Ok(expectedOutputType)) +// }) +// }) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 7ac42686..2b54e0fe 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -303,10 +303,13 @@ module Matcher = { } let findMatches = (r: registry, fnName: string, args: array) => { - switch _findExactMatches(r, fnName, args) { + let fnNameInParts = Js.String.split(".", fnName) + let fnToSearch = E.A.get(fnNameInParts, 1) |> E.O.default(fnNameInParts[0]) + + switch _findExactMatches(r, fnToSearch, args) { | Some(r) => Match.FullMatch(r) | None => - switch _findNameMatches(r, fnName, args) { + switch _findNameMatches(r, fnToSearch, args) { | Some(r) => Match.SameNameDifferentArguments(r) | None => Match.DifferentName } @@ -349,9 +352,6 @@ module FnDefinition = { let toFfiFn = (t: t): Reducer_Expression_T.optionFfiFn => (args, environment) => run(t, args, environment)->E.R.toOption - let toLambda = (t: t) => - Reducer_Module.convertOptionToFfiFn(t.name, toFfiFn(t))->Reducer_Module.eLambdaFFIValue - let make = (~name, ~inputs, ~run, ()): t => { name: name, inputs: inputs, @@ -405,39 +405,40 @@ module NameSpace = { let definitions = (t: t) => t.functions->E.A2.fmap(f => f.definitions)->E.A.concatMany let uniqueFnNames = (t: t) => definitions(t)->E.A2.fmap(r => r.name)->E.A.uniq let nameToDefinitions = (t: t, name: string) => definitions(t)->E.A2.filter(r => r.name == name) - - //todo: It could be good to set a warning if two definitions are both valid, but I don't expect this often. - let nameFfiFn = (t: t, name: string): Reducer_Expression_T.optionFfiFn => { - (args, environment) => { - let definitions = - nameToDefinitions(t, name)->E.A2.fmap((def, ()) => - FnDefinition.isMatch(def, args) - ? FnDefinition.run(def, args, environment) |> E.R.toOption - : None - ) - E.A.O.firstSomeFn(definitions) - } - } - - let toModule = (t: t): Reducer_Module.t => - E.A.reduce(uniqueFnNames(t), Reducer_Module.emptyStdLib, (acc, uniqueName) => { - let relevantDefinitions = nameFfiFn(t, uniqueName) - acc->Reducer_Module.defineFunction(uniqueName, relevantDefinitions) - }) } module Registry = { let toJson = (r: registry) => r->E.A2.fmap(Function.toJson) - let allExamples = (r: registry) => r->E.A2.fmap(r => r.examples)->E.A.concatMany let allExamplesWithFns = (r: registry) => r->E.A2.fmap(fn => fn.examples->E.A2.fmap(example => (fn, example)))->E.A.concatMany + let allDefinitionsWithFns = (r: registry) => + r->E.A2.fmap(fn => fn.definitions->E.A2.fmap(definitions => (fn, definitions)))->E.A.concatMany + + let cache = (r: registry): Js.Dict.t> => { + let functionsWithFnNames = + allDefinitionsWithFns(r) + ->E.A2.fmap(((fn, def)) => { + let nameWithNamespace = `${fn.nameSpace}.${def.name}` + let nameWithoutNamespace = def.name + fn.requiresNamespace + ? [(nameWithNamespace, fn)] + : [(nameWithNamespace, fn), (nameWithoutNamespace, fn)] + }) + ->E.A.concatMany + let uniqueNames = functionsWithFnNames->E.A2.fmap(((name, _)) => name)->E.A.uniq + let cacheAsArray: array<(string, array)> = uniqueNames->E.A2.fmap(uniqueName => { + let relevantItems = + E.A2.filter(functionsWithFnNames, ((defName, _)) => defName == uniqueName)->E.A2.fmap( + E.Tuple2.second, + ) + (uniqueName, relevantItems) + }) + cacheAsArray->Js.Dict.fromArray + } + let _exportedSubset = (r: registry): registry => r |> E.A.filter(r => !r.requiresNamespace) - - let definitionsWithFunctions = (r: registry) => - r->E.A2.fmap(fn => fn.definitions->E.A2.fmap(def => (def, fn)))->E.A.concatMany - /* There's a (potential+minor) bug here: If a function definition is called outside of the calls to the registry, then it's possible that there could be a match after the registry is @@ -449,7 +450,10 @@ module Registry = { ~args: array, ~env: GenericDist.env, ) => { - let matchToDef = m => Matcher.Registry.matchToDef(registry, m) + let cc = cache(registry) + let relevantFunctions = Js.Dict.get(cc, fnName) |> E.O.default([]) + + let matchToDef = m => Matcher.Registry.matchToDef(relevantFunctions, m) let showNameMatchDefinitions = matches => { let defs = matches @@ -460,7 +464,8 @@ module Registry = { ->E.A2.joinWith("; ") `There are function matches for ${fnName}(), but with different arguments: ${defs}` } - switch Matcher.Registry.findMatches(registry, fnName, args) { + + switch Matcher.Registry.findMatches(relevantFunctions, fnName, args) { | Matcher.Match.FullMatch(match) => match->matchToDef->E.O2.fmap(FnDefinition.run(_, args, env)) | SameNameDifferentArguments(m) => Some(Error(showNameMatchDefinitions(m))) | _ => None @@ -476,20 +481,4 @@ module Registry = { E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), ) } - - let allNamespaces = (t: registry) => t->E.A2.fmap(r => r.nameSpace)->E.A.uniq - - let makeBindings = (prevBindings: Reducer_Module.t, t: registry): Reducer_Module.t => { - let nameSpaces = allNamespaces(t) - let nameSpaceBindings = nameSpaces->E.A2.fmap(nameSpace => { - let namespaceModule: NameSpace.t = { - name: nameSpace, - functions: t->E.A2.filter(r => r.nameSpace == nameSpace), - } - (nameSpace, NameSpace.toModule(namespaceModule)) - }) - E.A.reduce(nameSpaceBindings, prevBindings, (acc, (name, fn)) => - acc->Reducer_Module.defineModule(name, fn) - ) - } } diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res index 61493165..5c1a9c30 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_StdLib.res @@ -1,7 +1,6 @@ module Bindings = Reducer_Bindings let internalStdLib = Bindings.emptyBindings->SquiggleLibrary_Math.makeBindings - ->FunctionRegistry_Core.Registry.makeBindings(FunctionRegistry_Library.registry) @genType let externalStdLib = internalStdLib->Bindings.toTypeScriptBindings From ffaf349e0aa2f998b023f4c112d4d93aa1032981 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Tue, 19 Jul 2022 11:33:11 +1000 Subject: [PATCH 31/40] Basic mapSampleN support --- .../Reducer_Dispatch_BuiltIn_test.res | 4 +++ .../SampleSetDist/SampleSetDist.res | 5 ++++ .../Reducer_Dispatch_BuiltIn.res | 26 +++++++++++++++++-- .../squiggle-lang/src/rescript/Utility/E.res | 13 ++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res index 98192d31..65048ebb 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn_test.res @@ -21,6 +21,10 @@ describe("builtin", () => { "addOne(t)=t+1; toList(mapSamples(fromSamples([1,2,3,4,5,6]), addOne))", "Ok([2,3,4,5,6,7])", ) + testEval( + "toList(mapSamplesN([fromSamples([1,2,3,4,5,6]), fromSamples([6, 5, 4, 3, 2, 1])], {|x| x[0] > x[1] ? x[0] : x[1]}))", + "Ok([6,5,4,4,5,6])", + ) }) describe("builtin exception", () => { diff --git a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res index bfbaa795..dc15f7a1 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/SampleSetDist/SampleSetDist.res @@ -117,6 +117,11 @@ let map3 = ( ): result => E.A.zip3(get(t1), get(t2), get(t3))->E.A2.fmap(E.Tuple3.toFnCall(fn))->_fromSampleResultArray +let mapN = (~fn: array => result, ~t1: array): result< + t, + sampleSetError, +> => E.A.transpose(E.A.fmap(get, t1))->E.A2.fmap(fn)->_fromSampleResultArray + let mean = t => T.get(t)->E.A.Floats.mean let geomean = t => T.get(t)->E.A.Floats.geomean let mode = t => T.get(t)->E.A.Floats.mode 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 484b0acb..c7ab817e 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 @@ -19,6 +19,15 @@ open Reducer_ErrorValue exception TestRescriptException +let parseSampleSetArray = (arr: array): option> => { + let parseSampleSet = (value: internalExpressionValue): option => + switch value { + | IEvDistribution(SampleSet(dist)) => Some(dist) + | _ => None + } + E.A.O.openIfAllSome(E.A.fmap(parseSampleSet, arr)) +} + let callInternal = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result< 'b, errorValue, @@ -149,6 +158,11 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b), IEvNumber(c)}) SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType } + + let mapN = (t1: array, aLambdaValue) => { + let fn = a => doLambdaCall(aLambdaValue, list{IEvArray(E.A.fmap(x => IEvNumber(x), a))}) + SampleSetDist.mapN(~fn, ~t1)->toType + } } let doReduceArray = (aValueArray, initialValue, aLambdaValue) => { @@ -230,6 +244,12 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce ], ) => SampleMap.map3(dist1, dist2, dist3, aLambdaValue) + | ("mapSamplesN", [IEvArray(aValueArray), IEvLambda(aLambdaValue)]) => + switch parseSampleSetArray(aValueArray) { + | Some(sampleSetArr) => SampleMap.mapN(sampleSetArr, aLambdaValue) + | None => + Error(REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)) + } | ("reduce", [IEvArray(aValueArray), initialValue, IEvLambda(aLambdaValue)]) => doReduceArray(aValueArray, initialValue, aLambdaValue) | ("reduceReverse", [IEvArray(aValueArray), initialValue, IEvLambda(aLambdaValue)]) => @@ -246,7 +266,6 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce Error(REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)) // Report full type signature as error } } - /* Reducer uses Result monad while reducing expressions */ @@ -262,5 +281,8 @@ let dispatch = (call: functionCall, environment, reducer: ExpressionT.reducerFn) 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 + | err => { + Js.Console.log(err) + RETodo("unhandled rescript exception")->Error + } } diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index fd328a1c..f593cd48 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -631,6 +631,19 @@ module A = { ) let filter = Js.Array.filter let joinWith = Js.Array.joinWith + let transpose = (xs: array>): array> => { + let arr: array> = [] + for i in 0 to length(xs) - 1 { + for j in 0 to length(xs[i]) - 1 { + if Js.Array.length(arr) <= j { + ignore(Js.Array.push([xs[i][j]], arr)) + } else { + ignore(Js.Array.push(xs[i][j], arr[j])) + } + } + } + arr + } let all = (p: 'a => bool, xs: array<'a>): bool => length(filter(p, xs)) == length(xs) let any = (p: 'a => bool, xs: array<'a>): bool => length(filter(p, xs)) > 0 From 5bdc19f35f66986ed7f8b395ae547a99f90faba4 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Tue, 19 Jul 2022 11:38:43 +1000 Subject: [PATCH 32/40] Refactor sampleN code and remove log --- .../Reducer_Dispatch_BuiltIn.res | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 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 c7ab817e..40903521 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 @@ -19,15 +19,6 @@ open Reducer_ErrorValue exception TestRescriptException -let parseSampleSetArray = (arr: array): option> => { - let parseSampleSet = (value: internalExpressionValue): option => - switch value { - | IEvDistribution(SampleSet(dist)) => Some(dist) - | _ => None - } - E.A.O.openIfAllSome(E.A.fmap(parseSampleSet, arr)) -} - let callInternal = (call: functionCall, environment, reducer: ExpressionT.reducerFn): result< 'b, errorValue, @@ -159,9 +150,25 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType } - let mapN = (t1: array, aLambdaValue) => { - let fn = a => doLambdaCall(aLambdaValue, list{IEvArray(E.A.fmap(x => IEvNumber(x), a))}) - SampleSetDist.mapN(~fn, ~t1)->toType + let mapN = (aValueArray: array, aLambdaValue) => { + switch parseSampleSetArray(aValueArray) { + | Some(t1) => + let fn = a => doLambdaCall(aLambdaValue, list{IEvArray(E.A.fmap(x => IEvNumber(x), a))}) + SampleSetDist.mapN(~fn, ~t1)->toType + | None => + Error(REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)) + } + } + + let parseSampleSetArray = (arr: array): option< + array, + > => { + let parseSampleSet = (value: internalExpressionValue): option => + switch value { + | IEvDistribution(SampleSet(dist)) => Some(dist) + | _ => None + } + E.A.O.openIfAllSome(E.A.fmap(parseSampleSet, arr)) } } @@ -245,11 +252,7 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce ) => SampleMap.map3(dist1, dist2, dist3, aLambdaValue) | ("mapSamplesN", [IEvArray(aValueArray), IEvLambda(aLambdaValue)]) => - switch parseSampleSetArray(aValueArray) { - | Some(sampleSetArr) => SampleMap.mapN(sampleSetArr, aLambdaValue) - | None => - Error(REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)) - } + SampleMap.mapN(aValueArray, aLambdaValue) | ("reduce", [IEvArray(aValueArray), initialValue, IEvLambda(aLambdaValue)]) => doReduceArray(aValueArray, initialValue, aLambdaValue) | ("reduceReverse", [IEvArray(aValueArray), initialValue, IEvLambda(aLambdaValue)]) => @@ -281,8 +284,5 @@ let dispatch = (call: functionCall, environment, reducer: ExpressionT.reducerFn) ExternalLibrary.dispatch((Js.String.make(fn), args), environment, callInternalWithReducer) } catch { | Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error - | err => { - Js.Console.log(err) - RETodo("unhandled rescript exception")->Error - } + | _ => RETodo("unhandled rescript exception")->Error } From 7887256ca10f5697d03e934866dbd5782cd502b8 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Tue, 19 Jul 2022 11:45:07 +1000 Subject: [PATCH 33/40] Reorder function declarations to compile --- .../Reducer_Dispatch_BuiltIn.res | 20 +++++++++---------- 1 file changed, 10 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 40903521..f0d8b3ab 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 @@ -150,16 +150,6 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType } - let mapN = (aValueArray: array, aLambdaValue) => { - switch parseSampleSetArray(aValueArray) { - | Some(t1) => - let fn = a => doLambdaCall(aLambdaValue, list{IEvArray(E.A.fmap(x => IEvNumber(x), a))}) - SampleSetDist.mapN(~fn, ~t1)->toType - | None => - Error(REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)) - } - } - let parseSampleSetArray = (arr: array): option< array, > => { @@ -170,6 +160,16 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce } E.A.O.openIfAllSome(E.A.fmap(parseSampleSet, arr)) } + + let mapN = (aValueArray: array, aLambdaValue) => { + switch parseSampleSetArray(aValueArray) { + | Some(t1) => + let fn = a => doLambdaCall(aLambdaValue, list{IEvArray(E.A.fmap(x => IEvNumber(x), a))}) + SampleSetDist.mapN(~fn, ~t1)->toType + | None => + Error(REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)) + } + } } let doReduceArray = (aValueArray, initialValue, aLambdaValue) => { From 938b20b4cdb25f808a2aac3309661975b014cc65 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Tue, 19 Jul 2022 12:38:05 +1000 Subject: [PATCH 34/40] Print error messages when functions fail --- .../src/components/FunctionChart.tsx | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/components/src/components/FunctionChart.tsx b/packages/components/src/components/FunctionChart.tsx index 05e4d393..73378cd8 100644 --- a/packages/components/src/components/FunctionChart.tsx +++ b/packages/components/src/components/FunctionChart.tsx @@ -1,5 +1,10 @@ import * as React from "react"; -import { lambdaValue, environment, runForeign } from "@quri/squiggle-lang"; +import { + lambdaValue, + environment, + runForeign, + errorValueToString, +} from "@quri/squiggle-lang"; import { FunctionChart1Dist } from "./FunctionChart1Dist"; import { FunctionChart1Number } from "./FunctionChart1Number"; import { DistributionPlottingSettings } from "./DistributionChart"; @@ -45,10 +50,16 @@ export const FunctionChart: React.FC = ({ } }; const validResult = getValidResult(); - const resultType = - validResult.tag === "Ok" ? validResult.value.tag : ("Error" as const); - switch (resultType) { + if (validResult.tag === "Error") { + return ( + + {errorValueToString(validResult.value)} + + ); + } + + switch (validResult.value.tag) { case "distribution": return ( = ({ height={height} /> ); - case "Error": - return ( - The function failed to be run - ); default: return ( There is no function visualization for this type of output:{" "} - {resultType} + {validResult.value.tag} ); } From 03edf60663126d6cdd4af76085ff1ed5630cf298 Mon Sep 17 00:00:00 2001 From: Sam Nolan Date: Tue, 19 Jul 2022 13:08:45 +1000 Subject: [PATCH 35/40] Show x coordinate when drawing discrete distributions --- packages/components/src/lib/distributionSpecBuilder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/lib/distributionSpecBuilder.ts b/packages/components/src/lib/distributionSpecBuilder.ts index 7a5bcd2f..d04f0c44 100644 --- a/packages/components/src/lib/distributionSpecBuilder.ts +++ b/packages/components/src/lib/distributionSpecBuilder.ts @@ -223,7 +223,7 @@ export function buildVegaSpec( }, size: [{ value: 100 }], tooltip: { - signal: "datum.y", + signal: "{ probability: datum.y, value: datum.x }", }, }, update: { From 905d2fbb23c1772f0ad1a32c42ca76e813759c45 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 18 Jul 2022 21:29:46 -0700 Subject: [PATCH 36/40] Removed now-uneeded Function Registry test file --- .../__tests__/FunctionRegistry_test.res | 93 ------------------- .../FunctionRegistry_Core.res | 3 +- 2 files changed, 1 insertion(+), 95 deletions(-) delete mode 100644 packages/squiggle-lang/__tests__/FunctionRegistry_test.res diff --git a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res b/packages/squiggle-lang/__tests__/FunctionRegistry_test.res deleted file mode 100644 index 6ee66f60..00000000 --- a/packages/squiggle-lang/__tests__/FunctionRegistry_test.res +++ /dev/null @@ -1,93 +0,0 @@ -module InternalExpressionValue = ReducerInterface_InternalExpressionValue -module ExpressionT = Reducer_Expression_T -// module Module = Reducer_Module -// module Bindings = Reducer_Module -module ErrorValue = Reducer_ErrorValue - -open Jest -open Expect - -// ---------------------- -// --- Start of Module File -// ---------------------- - -module FooImplementation = { - open FunctionRegistry_Core - open FunctionRegistry_Helpers - - let fn1 = Function.make( - ~name="add", - ~nameSpace="Foo", - ~requiresNamespace=false, - ~examples=["Foo.add2(1, 2)", "Foo.add3(1, 2, 3)"], - ~output=EvtNumber, - ~definitions=[ - FnDefinition.make( - ~name="add2", - ~inputs=[FRTypeNumber, FRTypeNumber], - ~run=(_, inputs, _) => - switch inputs { - | [FRValueNumber(a), FRValueNumber(b)] => Ok(Wrappers.evNumber(a +. b)) - | _ => Error("False") - }, - (), - ), - FnDefinition.make( - ~name="add3", - ~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber], - ~run=(_, inputs, _) => - switch inputs { - | [FRValueNumber(a), FRValueNumber(b), FRValueNumber(c)] => - Ok(Wrappers.evNumber(a +. b +. c)) - | _ => Error("False") - }, - (), - ), - ], - (), - ) - - let library = [fn1] -} - -// let makeBindings = FunctionRegistry_Core.Registry.makeBindings(_, FooImplementation.library) - -// let stdLibWithFoo = Bindings.emptyBindings->makeBindings - -// let evalWithFoo = sourceCode => -// Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr => -// Reducer_Expression.reduceExpression( -// expr, -// stdLibWithFoo, -// InternalExpressionValue.defaultEnvironment, -// ) -// ) - -// let evalToStringResultWithFoo = sourceCode => -// evalWithFoo(sourceCode)->InternalExpressionValue.toStringResult - -// describe("Module", () => { -// test("add2(1,2)", () => { -// let result = evalToStringResultWithFoo("Foo.add2(1,2)") -// expect(result)->toEqual("Ok(3)") -// }) -// test("add3(1,2,3)", () => { -// let result = evalToStringResultWithFoo("Foo.add3(1,2,3)") -// expect(result)->toEqual("Ok(6)") -// }) -// }) - -// describe("Fn auto-testing", () => { -// let items = FooImplementation.fn1.examples->E.A.to_list - -// testAll("tests of validity", items, r => { -// expect(r->evalWithFoo->E.R.isOk)->toEqual(true) -// }) - -// testAll("tests of type", items, r => { -// let responseType = -// r->evalWithFoo->E.R2.fmap(ReducerInterface_InternalExpressionValue.valueToValueType) -// let expectedOutputType = FooImplementation.fn1.output |> E.O.toExn("") -// expect(responseType)->toEqual(Ok(expectedOutputType)) -// }) -// }) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 2b54e0fe..e7abc961 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -438,7 +438,6 @@ module Registry = { cacheAsArray->Js.Dict.fromArray } - let _exportedSubset = (r: registry): registry => r |> E.A.filter(r => !r.requiresNamespace) /* There's a (potential+minor) bug here: If a function definition is called outside of the calls to the registry, then it's possible that there could be a match after the registry is @@ -477,7 +476,7 @@ module Registry = { (fnName, args): ReducerInterface_InternalExpressionValue.functionCall, env, ) => { - _matchAndRun(~registry=_exportedSubset(registry), ~fnName, ~args, ~env)->E.O2.fmap( + _matchAndRun(~registry, ~fnName, ~args, ~env)->E.O2.fmap( E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), ) } From dbfee988d26f421be461d1a8d415cad5f3a06477 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 18 Jul 2022 22:14:46 -0700 Subject: [PATCH 37/40] Pulled out cache in Registry, to make more sense --- .../FunctionRegistry_Core.res | 40 +++++++++++-------- .../FunctionRegistry_Library.res | 5 ++- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index e7abc961..93b99f34 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -61,7 +61,8 @@ type function = { isExperimental: bool, } -type registry = array +type fnNameDict = Js.Dict.t> +type registry = {functions: array, fnNameDict: fnNameDict} module FRType = { type t = frType @@ -273,7 +274,8 @@ module Matcher = { module Registry = { let _findExactMatches = (r: registry, fnName: string, args: array) => { - let functionMatchPairs = r->E.A2.fmap(l => (l, Function.match(l, fnName, args))) + let functionMatchPairs = + r.functions->E.A2.fmap(l => (l, Function.match(l, fnName, args))) let fullMatch = functionMatchPairs->E.A.getBy(((_, match)) => Match.isFullMatch(match)) fullMatch->E.O.bind(((fn, match)) => switch match { @@ -284,7 +286,7 @@ module Matcher = { } let _findNameMatches = (r: registry, fnName: string, args: array) => { - let functionMatchPairs = r->E.A2.fmap(l => (l, Function.match(l, fnName, args))) + let functionMatchPairs = r.functions->E.A2.fmap(l => (l, Function.match(l, fnName, args))) let getNameMatches = functionMatchPairs ->E.A2.fmap(((fn, match)) => Match.isNameMatchOnly(match) ? Some((fn, match)) : None) @@ -319,7 +321,7 @@ module Matcher = { let matchToDef = (registry: registry, {fnName, inputIndex}: RegistryMatch.match): option< fnDefinition, > => - registry + registry.functions ->E.A.getBy(fn => fn.name === fnName) ->E.O.bind(fn => E.A.get(fn.definitions, inputIndex)) } @@ -408,17 +410,17 @@ module NameSpace = { } module Registry = { - let toJson = (r: registry) => r->E.A2.fmap(Function.toJson) - let allExamples = (r: registry) => r->E.A2.fmap(r => r.examples)->E.A.concatMany + let toJson = (r: registry) => r.functions->E.A2.fmap(Function.toJson) + let allExamples = (r: registry) => r.functions->E.A2.fmap(r => r.examples)->E.A.concatMany let allExamplesWithFns = (r: registry) => - r->E.A2.fmap(fn => fn.examples->E.A2.fmap(example => (fn, example)))->E.A.concatMany + r.functions->E.A2.fmap(fn => fn.examples->E.A2.fmap(example => (fn, example)))->E.A.concatMany - let allDefinitionsWithFns = (r: registry) => - r->E.A2.fmap(fn => fn.definitions->E.A2.fmap(definitions => (fn, definitions)))->E.A.concatMany - - let cache = (r: registry): Js.Dict.t> => { + let buildFnNameDict = (r: array): fnNameDict => { + let allDefinitionsWithFns = r + ->E.A2.fmap(fn => fn.definitions->E.A2.fmap(definitions => (fn, definitions))) + ->E.A.concatMany let functionsWithFnNames = - allDefinitionsWithFns(r) + allDefinitionsWithFns ->E.A2.fmap(((fn, def)) => { let nameWithNamespace = `${fn.nameSpace}.${def.name}` let nameWithoutNamespace = def.name @@ -438,6 +440,11 @@ module Registry = { cacheAsArray->Js.Dict.fromArray } + let make = (fns: array):registry => { + let dict = buildFnNameDict(fns) + {functions: fns, fnNameDict: dict} + } + /* There's a (potential+minor) bug here: If a function definition is called outside of the calls to the registry, then it's possible that there could be a match after the registry is @@ -449,10 +456,9 @@ module Registry = { ~args: array, ~env: GenericDist.env, ) => { - let cc = cache(registry) - let relevantFunctions = Js.Dict.get(cc, fnName) |> E.O.default([]) - - let matchToDef = m => Matcher.Registry.matchToDef(relevantFunctions, m) + let relevantFunctions = Js.Dict.get(registry.fnNameDict, fnName) |> E.O.default([]) + let modified = {functions: relevantFunctions, fnNameDict: registry.fnNameDict} + let matchToDef = m => Matcher.Registry.matchToDef(registry, m) let showNameMatchDefinitions = matches => { let defs = matches @@ -464,7 +470,7 @@ module Registry = { `There are function matches for ${fnName}(), but with different arguments: ${defs}` } - switch Matcher.Registry.findMatches(relevantFunctions, fnName, args) { + switch Matcher.Registry.findMatches(modified, fnName, args) { | Matcher.Match.FullMatch(match) => match->matchToDef->E.O2.fmap(FnDefinition.run(_, args, env)) | SameNameDifferentArguments(m) => Some(Error(showNameMatchDefinitions(m))) | _ => None diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 52a424e0..1699ef96 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -1,4 +1,4 @@ -let registry = Belt.Array.concatMany([ +let fnList = Belt.Array.concatMany([ FR_Dict.library, FR_Dist.library, FR_Fn.library, @@ -8,4 +8,5 @@ let registry = Belt.Array.concatMany([ FR_Scoring.library, ]) -let dispatch = FunctionRegistry_Core.Registry.dispatch(registry) +let registry = FunctionRegistry_Core.Registry.make(fnList) +let dispatch = FunctionRegistry_Core.Registry.dispatch(registry) \ No newline at end of file From 173c17e13dd9f848b8b3fb9436f82fc9df4d5e47 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 18 Jul 2022 22:17:38 -0700 Subject: [PATCH 38/40] Simple cleanup --- .../ReducerInterface_ExternalLibrary.res | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res index 312dfd38..8a121cd0 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res @@ -16,3 +16,16 @@ let dispatch = (call: InternalExpressionValue.functionCall, environment, chain): () => FunctionRegistry_Library.dispatch(call, environment), ])->E.O2.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. +The final chain(call) invokes the builtin default functions of the interpreter. +Via chain(call), all MathJs operators and functions are available for string, number , boolean, array and record + .e.g + - / * > >= < <= == /= not and or sin cos log ln concat, etc. +// See https://mathjs.org/docs/expressions/syntax.html +// See https://mathjs.org/docs/reference/functions.html +Remember from the users point of view, there are no different modules: +// "doSth( constructorType1 )" +// "doSth( constructorType2 )" +doSth gets dispatched to the correct module because of the type signature. You get function and operator abstraction for free. You don't need to combine different implementations into one type. That would be duplicating the repsonsibility of the dispatcher. +*/ \ No newline at end of file From 6f25fca814710192927b2b64969387ec90a6ebdf Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 18 Jul 2022 22:21:57 -0700 Subject: [PATCH 39/40] Minor cleanup --- .../FunctionRegistry/FunctionRegistry_Core.res | 12 ++++++------ .../FunctionRegistry/FunctionRegistry_Library.res | 2 +- .../ReducerInterface_ExternalLibrary.res | 6 +++++- .../SquiggleLibrary/SquiggleLibrary_Math.res | 1 - 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 93b99f34..9d1c6669 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -274,8 +274,7 @@ module Matcher = { module Registry = { let _findExactMatches = (r: registry, fnName: string, args: array) => { - let functionMatchPairs = - r.functions->E.A2.fmap(l => (l, Function.match(l, fnName, args))) + let functionMatchPairs = r.functions->E.A2.fmap(l => (l, Function.match(l, fnName, args))) let fullMatch = functionMatchPairs->E.A.getBy(((_, match)) => Match.isFullMatch(match)) fullMatch->E.O.bind(((fn, match)) => switch match { @@ -416,9 +415,10 @@ module Registry = { r.functions->E.A2.fmap(fn => fn.examples->E.A2.fmap(example => (fn, example)))->E.A.concatMany let buildFnNameDict = (r: array): fnNameDict => { - let allDefinitionsWithFns = r - ->E.A2.fmap(fn => fn.definitions->E.A2.fmap(definitions => (fn, definitions))) - ->E.A.concatMany + let allDefinitionsWithFns = + r + ->E.A2.fmap(fn => fn.definitions->E.A2.fmap(definitions => (fn, definitions))) + ->E.A.concatMany let functionsWithFnNames = allDefinitionsWithFns ->E.A2.fmap(((fn, def)) => { @@ -440,7 +440,7 @@ module Registry = { cacheAsArray->Js.Dict.fromArray } - let make = (fns: array):registry => { + let make = (fns: array): registry => { let dict = buildFnNameDict(fns) {functions: fns, fnNameDict: dict} } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 1699ef96..9b0f6737 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -9,4 +9,4 @@ let fnList = Belt.Array.concatMany([ ]) let registry = FunctionRegistry_Core.Registry.make(fnList) -let dispatch = FunctionRegistry_Core.Registry.dispatch(registry) \ No newline at end of file +let dispatch = FunctionRegistry_Core.Registry.dispatch(registry) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res index 8a121cd0..43a1375c 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExternalLibrary.res @@ -19,13 +19,17 @@ let dispatch = (call: InternalExpressionValue.functionCall, environment, chain): /* If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally. + The final chain(call) invokes the builtin default functions of the interpreter. + Via chain(call), all MathJs operators and functions are available for string, number , boolean, array and record .e.g + - / * > >= < <= == /= not and or sin cos log ln concat, etc. + // See https://mathjs.org/docs/expressions/syntax.html // See https://mathjs.org/docs/reference/functions.html + Remember from the users point of view, there are no different modules: // "doSth( constructorType1 )" // "doSth( constructorType2 )" doSth gets dispatched to the correct module because of the type signature. You get function and operator abstraction for free. You don't need to combine different implementations into one type. That would be duplicating the repsonsibility of the dispatcher. -*/ \ No newline at end of file +*/ diff --git a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res index 50c8dd2f..ce74f476 100644 --- a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res +++ b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res @@ -18,6 +18,5 @@ let mathBindings: Bindings.t = ->E.A2.fmap(((name, v)) => (name, ReducerInterface_InternalExpressionValue.IEvNumber(v))) ->Bindings.fromArray -//TODO: This should be in a different place. let makeBindings = (previousBindings: Bindings.t): Bindings.t => previousBindings->Bindings.merge(mathBindings) From 28036bfb36ac504c2035062a7eb5c37dd517cf6d Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 19 Jul 2022 08:12:04 -0700 Subject: [PATCH 40/40] Minor cleanup --- ...leLibrary_FunctionRegistryLibrary_test.res | 130 +++++++++--------- .../FunctionRegistry_Core.res | 7 +- 2 files changed, 68 insertions(+), 69 deletions(-) diff --git a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res index 77052d9b..d4f52e5c 100644 --- a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res +++ b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res @@ -8,71 +8,73 @@ let expectEvalToBeOk = (expr: string) => let registry = FunctionRegistry_Library.registry let examples = E.A.to_list(FunctionRegistry_Core.Registry.allExamples(registry)) -describe("Fn auto-testing", () => { - testAll("tests of validity", examples, r => { - expectEvalToBeOk(r) +describe("FunctionRegistry Library", () => { + describe("Regular tests", () => { + testEvalToBe("List.make(3, 'HI')", "Ok(['HI','HI','HI'])") + testEvalToBe("make(3, 'HI')", "Error(Function not found: make(Number,String))") + testEvalToBe("List.upTo(1,3)", "Ok([1,2,3])") + testEvalToBe("List.first([3,5,8])", "Ok(3)") + testEvalToBe("List.last([3,5,8])", "Ok(8)") + testEvalToBe("List.reverse([3,5,8])", "Ok([8,5,3])") + testEvalToBe("Dist.normal(5,2)", "Ok(Normal(5,2))") + testEvalToBe("normal(5,2)", "Ok(Normal(5,2))") + testEvalToBe("normal({mean:5,stdev:2})", "Ok(Normal(5,2))") + testEvalToBe("-2 to 4", "Ok(Normal(1,1.8238704957353074))") + testEvalToBe("pointMass(5)", "Ok(PointMass(5))") + testEvalToBe("Number.floor(5.5)", "Ok(5)") + testEvalToBe("Number.ceil(5.5)", "Ok(6)") + testEvalToBe("floor(5.5)", "Ok(5)") + testEvalToBe("ceil(5.5)", "Ok(6)") + testEvalToBe("Number.abs(5.5)", "Ok(5.5)") + testEvalToBe("abs(5.5)", "Ok(5.5)") + testEvalToBe("Number.exp(10)", "Ok(22026.465794806718)") + testEvalToBe("Number.log10(10)", "Ok(1)") + testEvalToBe("Number.log2(10)", "Ok(3.321928094887362)") + testEvalToBe("Number.sum([2,5,3])", "Ok(10)") + testEvalToBe("sum([2,5,3])", "Ok(10)") + testEvalToBe("Number.product([2,5,3])", "Ok(30)") + testEvalToBe("Number.min([2,5,3])", "Ok(2)") + testEvalToBe("Number.max([2,5,3])", "Ok(5)") + testEvalToBe("Number.mean([0,5,10])", "Ok(5)") + testEvalToBe("Number.geomean([1,5,18])", "Ok(4.481404746557164)") + testEvalToBe("Number.stdev([0,5,10,15])", "Ok(5.5901699437494745)") + testEvalToBe("Number.variance([0,5,10,15])", "Ok(31.25)") + testEvalToBe("Number.sort([10,0,15,5])", "Ok([0,5,10,15])") + testEvalToBe("Number.cumsum([1,5,3])", "Ok([1,6,9])") + testEvalToBe("Number.cumprod([1,5,3])", "Ok([1,5,15])") + testEvalToBe("Number.diff([1,5,3])", "Ok([4,-2])") + testEvalToBe( + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1), prior: normal(5.5,3)})", + "Ok(-0.33591375663884876)", + ) + testEvalToBe( + "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)})", + "Ok(0.32244107041564646)", + ) + testEvalToBe("Dist.logScore({estimate: normal(5,2), answer: 4.5})", "Ok(1.6433360626394853)") + testEvalToBe("Dist.klDivergence(normal(5,2), normal(5,1.5))", "Ok(0.06874342818671068)") }) - testAll( - "tests of type", - E.A.to_list( - FunctionRegistry_Core.Registry.allExamplesWithFns(registry)->E.A2.filter(((fn, _)) => - E.O.isSome(fn.output) - ), - ), - ((fn, example)) => { - let responseType = - example - ->Reducer.evaluate - ->E.R2.fmap(ReducerInterface_InternalExpressionValue.externalValueToValueType) - let expectedOutputType = fn.output |> E.O.toExn("") - expect(responseType)->toEqual(Ok(expectedOutputType)) - }, - ) -}) + describe("Fn auto-testing", () => { + testAll("tests of validity", examples, r => { + expectEvalToBeOk(r) + }) -describe("FunctionRegistry Library", () => { - testEvalToBe("List.make(3, 'HI')", "Ok(['HI','HI','HI'])") - testEvalToBe("make(3, 'HI')", "Error(Function not found: make(Number,String))") - testEvalToBe("List.upTo(1,3)", "Ok([1,2,3])") - testEvalToBe("List.first([3,5,8])", "Ok(3)") - testEvalToBe("List.last([3,5,8])", "Ok(8)") - testEvalToBe("List.reverse([3,5,8])", "Ok([8,5,3])") - testEvalToBe("Dist.normal(5,2)", "Ok(Normal(5,2))") - testEvalToBe("normal(5,2)", "Ok(Normal(5,2))") - testEvalToBe("normal({mean:5,stdev:2})", "Ok(Normal(5,2))") - testEvalToBe("-2 to 4", "Ok(Normal(1,1.8238704957353074))") - testEvalToBe("pointMass(5)", "Ok(PointMass(5))") - testEvalToBe("Number.floor(5.5)", "Ok(5)") - testEvalToBe("Number.ceil(5.5)", "Ok(6)") - testEvalToBe("floor(5.5)", "Ok(5)") - testEvalToBe("ceil(5.5)", "Ok(6)") - testEvalToBe("Number.abs(5.5)", "Ok(5.5)") - testEvalToBe("abs(5.5)", "Ok(5.5)") - testEvalToBe("Number.exp(10)", "Ok(22026.465794806718)") - testEvalToBe("Number.log10(10)", "Ok(1)") - testEvalToBe("Number.log2(10)", "Ok(3.321928094887362)") - testEvalToBe("Number.sum([2,5,3])", "Ok(10)") - testEvalToBe("sum([2,5,3])", "Ok(10)") - testEvalToBe("Number.product([2,5,3])", "Ok(30)") - testEvalToBe("Number.min([2,5,3])", "Ok(2)") - testEvalToBe("Number.max([2,5,3])", "Ok(5)") - testEvalToBe("Number.mean([0,5,10])", "Ok(5)") - testEvalToBe("Number.geomean([1,5,18])", "Ok(4.481404746557164)") - testEvalToBe("Number.stdev([0,5,10,15])", "Ok(5.5901699437494745)") - testEvalToBe("Number.variance([0,5,10,15])", "Ok(31.25)") - testEvalToBe("Number.sort([10,0,15,5])", "Ok([0,5,10,15])") - testEvalToBe("Number.cumsum([1,5,3])", "Ok([1,6,9])") - testEvalToBe("Number.cumprod([1,5,3])", "Ok([1,5,15])") - testEvalToBe("Number.diff([1,5,3])", "Ok([4,-2])") - testEvalToBe( - "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1), prior: normal(5.5,3)})", - "Ok(-0.33591375663884876)", - ) - testEvalToBe( - "Dist.logScore({estimate: normal(5,2), answer: normal(5.2,1)})", - "Ok(0.32244107041564646)", - ) - testEvalToBe("Dist.logScore({estimate: normal(5,2), answer: 4.5})", "Ok(1.6433360626394853)") - testEvalToBe("Dist.klDivergence(normal(5,2), normal(5,1.5))", "Ok(0.06874342818671068)") + testAll( + "tests of type", + E.A.to_list( + FunctionRegistry_Core.Registry.allExamplesWithFns(registry)->E.A2.filter(((fn, _)) => + E.O.isSome(fn.output) + ), + ), + ((fn, example)) => { + let responseType = + example + ->Reducer.evaluate + ->E.R2.fmap(ReducerInterface_InternalExpressionValue.externalValueToValueType) + let expectedOutputType = fn.output |> E.O.toExn("") + expect(responseType)->toEqual(Ok(expectedOutputType)) + }, + ) + }) }) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 9d1c6669..25eb87b7 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -350,9 +350,6 @@ module FnDefinition = { } } - let toFfiFn = (t: t): Reducer_Expression_T.optionFfiFn => - (args, environment) => run(t, args, environment)->E.R.toOption - let make = (~name, ~inputs, ~run, ()): t => { name: name, inputs: inputs, @@ -414,7 +411,7 @@ module Registry = { let allExamplesWithFns = (r: registry) => r.functions->E.A2.fmap(fn => fn.examples->E.A2.fmap(example => (fn, example)))->E.A.concatMany - let buildFnNameDict = (r: array): fnNameDict => { + let _buildFnNameDict = (r: array): fnNameDict => { let allDefinitionsWithFns = r ->E.A2.fmap(fn => fn.definitions->E.A2.fmap(definitions => (fn, definitions))) @@ -441,7 +438,7 @@ module Registry = { } let make = (fns: array): registry => { - let dict = buildFnNameDict(fns) + let dict = _buildFnNameDict(fns) {functions: fns, fnNameDict: dict} }