From e0f4809ad73842ecf2fb3091166519eafe104c5d Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 17 May 2022 18:54:31 -0400 Subject: [PATCH 01/26] Function registry first attempt --- .../src/rescript/FunctionRegistry.res | 113 ++++++++++++++++++ .../squiggle-lang/src/rescript/Utility/E.res | 6 + 2 files changed, 119 insertions(+) create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry.res diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res new file mode 100644 index 00000000..ef44c269 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -0,0 +1,113 @@ +type expressionValue = ReducerInterface_ExpressionValue.expressionValue + +type rec itype = + I_Number | I_DistOrNumber | I_Record(iRecord) | I_Array(array) | I_Option(itype) +and iRecord = array +and iRecordParam = (string, itype) + +type rec value = + | Number(float) + | Dist(DistributionTypes.genericDist) + | Option(option) + | DistOrNumber(distOrNumber) + | Record(record) +and record = array<(string, value)> +and distOrNumber = Number(float) | Dist(DistributionTypes.genericDist) + +type runFn = array => result + +type fnDefinition = {name: string, inputs: array, run: runFn} + +type function = { + name: string, + definitions: array, +} + +let rec matchInput = (input: itype, r: expressionValue): option => + switch (input, r) { + | (I_Number, EvNumber(f)) => Some(Number(f)) + | (I_DistOrNumber, EvNumber(f)) => Some(DistOrNumber(Number(f))) + | (I_DistOrNumber, EvDistribution(f)) => Some(DistOrNumber(Dist(f))) + | (I_Option(v), _) => Some(Option(matchInput(v, r))) + | (I_Record(recordParams), EvRecord(record)) => { + let getAndMatch = (name, input) => + E.Dict.get(record, name)->E.O.bind(v => matchInput(input, v)) + let arrayOfNameValues: array<(Js.Dict.key, option)> = + recordParams->E.A2.fmap(((name, input)) => (name, getAndMatch(name, input))) + let hasNullValues = E.A.hasBy(arrayOfNameValues, ((_, value)) => E.O.isNone(value)) + if hasNullValues { + None + } else { + arrayOfNameValues + ->E.A2.fmap(((name, value)) => (name, value->E.O2.toExn(""))) + ->(r => Some(Record(r))) + } + } + | _ => None + } + +type match = DifferentName | SameNameDifferentArguments(string) | Match(string, array) + +let isFullMatch = (match: match) => + switch match { + | Match(_, _) => true + | _ => false + } + +let isNameMatchOnly = (match: match) => + switch match { + | SameNameDifferentArguments(_) => true + | _ => false + } + +let matchSingle = (f: fnDefinition, fnName: string, args: array) => { + if f.name !== fnName { + DifferentName + } else { + let inputTypes = f.inputs + if E.A.length(f.inputs) !== E.A.length(args) { + SameNameDifferentArguments(f.name) + } else { + let foo = + E.A.zip(inputTypes, args) + ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) + ->E.A.O.arrSomeToSomeArr + switch foo { + | Some(r) => Match(f.name, r) + | None => SameNameDifferentArguments(f.name) + } + } + } +} + +let getByOpen = (a,op,bin) => switch(E.A.getBy(a, r => bin(op(r)))) { + | Some(r) => Some(op(r)) + | None => None +} + +let match = (f: function, fnName: string, args: array) => { + let matchedDefinition = E.A.getBy(f.definitions, r => isFullMatch(matchSingle(r, fnName, args))) + switch matchedDefinition { + | Some(matchedDefinition) => { + let match = matchSingle(matchedDefinition, fnName, args) + switch match { + | Match(a, b) => Ok(Match(a, b)) + | _ => Error("Should be Impossible") + } + } + | None => { + let matchedNameDefinition = E.A.getBy(f.definitions, r => + isNameMatchOnly(matchSingle(r, fnName, args)) + ) + let foo = switch matchedNameDefinition { + | Some(matchedNameDefinition) => + switch matchSingle(matchedNameDefinition, fnName, args) { + | SameNameDifferentArguments(r) => Ok(SameNameDifferentArguments(r)) + | _ => Error("Should be Impossible") + } + | _ => Ok(DifferentName) + } + foo + } + } +} diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 64729324..4ed24ead 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -830,3 +830,9 @@ module JsArray = { |> Js.Array.map(O.toExn("Warning: This should not have happened")) let filter = Js.Array.filter } + +module Dict = { + type t<'a> = Js.Dict.t<'a> + let get = Js.Dict.get + let keys = Js.Dict.keys +} \ No newline at end of file From f30de20c8d24d24d48a2e4aebd085ce3b4723fc1 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 17 May 2022 20:45:32 -0400 Subject: [PATCH 02/26] Refactored match() code --- .../src/rescript/FunctionRegistry.res | 38 ++++--------------- .../squiggle-lang/src/rescript/Utility/E.res | 13 ++++++- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index ef44c269..5d94ff20 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -1,7 +1,7 @@ type expressionValue = ReducerInterface_ExpressionValue.expressionValue type rec itype = - I_Number | I_DistOrNumber | I_Record(iRecord) | I_Array(array) | I_Option(itype) + I_Number | I_Numeric | I_DistOrNumber | I_Record(iRecord) | I_Array(array) | I_Option(itype) and iRecord = array and iRecordParam = (string, itype) @@ -28,6 +28,8 @@ let rec matchInput = (input: itype, r: expressionValue): option => | (I_Number, EvNumber(f)) => Some(Number(f)) | (I_DistOrNumber, EvNumber(f)) => Some(DistOrNumber(Number(f))) | (I_DistOrNumber, EvDistribution(f)) => Some(DistOrNumber(Dist(f))) + | (I_Numeric, EvNumber(f)) => Some(Number(f)) + | (I_Numeric, EvDistribution(Symbolic(#Float(f)))) => Some((Number(f))) | (I_Option(v), _) => Some(Option(matchInput(v, r))) | (I_Record(recordParams), EvRecord(record)) => { let getAndMatch = (name, input) => @@ -80,34 +82,10 @@ let matchSingle = (f: fnDefinition, fnName: string, args: array } } -let getByOpen = (a,op,bin) => switch(E.A.getBy(a, r => bin(op(r)))) { - | Some(r) => Some(op(r)) - | None => None -} - let match = (f: function, fnName: string, args: array) => { - let matchedDefinition = E.A.getBy(f.definitions, r => isFullMatch(matchSingle(r, fnName, args))) - switch matchedDefinition { - | Some(matchedDefinition) => { - let match = matchSingle(matchedDefinition, fnName, args) - switch match { - | Match(a, b) => Ok(Match(a, b)) - | _ => Error("Should be Impossible") - } - } - | None => { - let matchedNameDefinition = E.A.getBy(f.definitions, r => - isNameMatchOnly(matchSingle(r, fnName, args)) - ) - let foo = switch matchedNameDefinition { - | Some(matchedNameDefinition) => - switch matchSingle(matchedNameDefinition, fnName, args) { - | SameNameDifferentArguments(r) => Ok(SameNameDifferentArguments(r)) - | _ => Error("Should be Impossible") - } - | _ => Ok(DifferentName) - } - foo - } - } + let matchedDefinition = () => + E.A.getByOpen(f.definitions, r => matchSingle(r, fnName, args), isFullMatch) + let getMatchedNameOnlyDefinition = () => + E.A.getByOpen(f.definitions, r => matchSingle(r, fnName, args), isNameMatchOnly) + E.A.O.firstSomeFnWithDefault([matchedDefinition, getMatchedNameOnlyDefinition], DifferentName) } diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 4ed24ead..c3cf855d 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -549,6 +549,12 @@ module A = { |> (x => Ok(x)) } + let getByOpen = (a, op, bin) => + switch getBy(a, r => bin(op(r))) { + | Some(r) => Some(op(r)) + | None => None + } + let tail = Belt.Array.sliceToEnd(_, 1) let zip = Belt.Array.zip @@ -633,6 +639,11 @@ module A = { } } let firstSome = x => Belt.Array.getBy(x, O.isSome) + + let firstSomeFn = (r: array option<'a>>): option<'a> => + O.flatten(getByOpen(r, l => l(), O.isSome)) + + let firstSomeFnWithDefault = (r, default) => firstSomeFn(r)->O2.default(default) } module R = { @@ -835,4 +846,4 @@ module Dict = { type t<'a> = Js.Dict.t<'a> let get = Js.Dict.get let keys = Js.Dict.keys -} \ No newline at end of file +} From 3085805a4d93a369943ad489e1cceb55fdbaf6bf Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Tue, 17 May 2022 21:16:26 -0400 Subject: [PATCH 03/26] Experiment with function registry for normal distribution --- .../src/rescript/FunctionRegistry.res | 66 ++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index 5d94ff20..766e3aaf 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -1,7 +1,12 @@ type expressionValue = ReducerInterface_ExpressionValue.expressionValue type rec itype = - I_Number | I_Numeric | I_DistOrNumber | I_Record(iRecord) | I_Array(array) | I_Option(itype) + | I_Number + | I_Numeric + | I_DistOrNumber + | I_Record(iRecord) + | I_Array(array) + | I_Option(itype) and iRecord = array and iRecordParam = (string, itype) @@ -14,7 +19,7 @@ type rec value = and record = array<(string, value)> and distOrNumber = Number(float) | Dist(DistributionTypes.genericDist) -type runFn = array => result +type runFn = array => result type fnDefinition = {name: string, inputs: array, run: runFn} @@ -23,13 +28,25 @@ type function = { definitions: array, } +module Function = { + let make = (name, definitions): function => { + name: name, + definitions: definitions, + } + let makeDefinition = (name, inputs, run): fnDefinition => { + name: name, + inputs: inputs, + run: run, + } +} + let rec matchInput = (input: itype, r: expressionValue): option => switch (input, r) { | (I_Number, EvNumber(f)) => Some(Number(f)) | (I_DistOrNumber, EvNumber(f)) => Some(DistOrNumber(Number(f))) | (I_DistOrNumber, EvDistribution(f)) => Some(DistOrNumber(Dist(f))) | (I_Numeric, EvNumber(f)) => Some(Number(f)) - | (I_Numeric, EvDistribution(Symbolic(#Float(f)))) => Some((Number(f))) + | (I_Numeric, EvDistribution(Symbolic(#Float(f)))) => Some(Number(f)) | (I_Option(v), _) => Some(Option(matchInput(v, r))) | (I_Record(recordParams), EvRecord(record)) => { let getAndMatch = (name, input) => @@ -89,3 +106,46 @@ let match = (f: function, fnName: string, args: array) => { E.A.getByOpen(f.definitions, r => matchSingle(r, fnName, args), isNameMatchOnly) E.A.O.firstSomeFnWithDefault([matchedDefinition, getMatchedNameOnlyDefinition], DifferentName) } + +let twoNumberInputs = (inputs: array) => + switch inputs { + | [Number(n1), Number(n2)] => Ok(n1, n2) + | _ => Error("Wrong inputs / Logically impossible") + } + +let twoNumberInputsRecord = (v1, v2, inputs: array) => + switch inputs { + | [Record([(name1, n1), (name2, n2)])] if name1 == v1 && name2 == v2 => twoNumberInputs([n1, n2]) + | _ => Error("Wrong inputs / Logically impossible") + } + +let contain = r => ReducerInterface_ExpressionValue.EvDistribution(Symbolic(r)) + +let meanStdev = (mean, stdev) => SymbolicDist.Normal.make(mean, stdev)->E.R2.fmap(contain) + +let p5and95 = (p5, p95) => contain(SymbolicDist.Normal.from90PercentCI(p5, p95)) + +let convertTwoInputs = (inputs: array): result => + twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) + +let normal = Function.make( + "Normal", + [ + Function.makeDefinition("normal", [I_Numeric, I_Numeric], inputs => + twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) + ), + Function.makeDefinition( + "normal", + [I_Record([("mean", I_Numeric), ("stdev", I_Numeric)])], + inputs => + twoNumberInputsRecord("mean", "stdev", inputs)->E.R.bind(((mean, stdev)) => + meanStdev(mean, stdev) + ), + ), + Function.makeDefinition("normal", [I_Record([("p5", I_Numeric), ("p95", I_Numeric)])], inputs => + twoNumberInputsRecord("p5", "p95", inputs)->E.R.bind(((mean, stdev)) => + meanStdev(mean, stdev) + ) + ), + ], +) From c1de95b39ae7c120e2cab0c6b708e3956d0734e7 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Wed, 18 May 2022 16:22:11 -0400 Subject: [PATCH 04/26] Added simple registry module --- .../src/rescript/FunctionRegistry.res | 149 ++++++++++++++++-- .../squiggle-lang/src/rescript/Utility/E.res | 3 + 2 files changed, 139 insertions(+), 13 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index 766e3aaf..84e5eccb 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -28,6 +28,8 @@ type function = { definitions: array, } +type registry = array + module Function = { let make = (name, definitions): function => { name: name, @@ -79,23 +81,27 @@ let isNameMatchOnly = (match: match) => | _ => false } +let matchSingleSameName = (f: fnDefinition, args: array) => { + let inputTypes = f.inputs + if E.A.length(f.inputs) !== E.A.length(args) { + SameNameDifferentArguments(f.name) + } else { + let foo = + E.A.zip(inputTypes, args) + ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) + ->E.A.O.arrSomeToSomeArr + switch foo { + | Some(r) => Match(f.name, r) + | None => SameNameDifferentArguments(f.name) + } + } +} + let matchSingle = (f: fnDefinition, fnName: string, args: array) => { if f.name !== fnName { DifferentName } else { - let inputTypes = f.inputs - if E.A.length(f.inputs) !== E.A.length(args) { - SameNameDifferentArguments(f.name) - } else { - let foo = - E.A.zip(inputTypes, args) - ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) - ->E.A.O.arrSomeToSomeArr - switch foo { - | Some(r) => Match(f.name, r) - | None => SameNameDifferentArguments(f.name) - } - } + matchSingleSameName(f, args) } } @@ -107,6 +113,123 @@ let match = (f: function, fnName: string, args: array) => { E.A.O.firstSomeFnWithDefault([matchedDefinition, getMatchedNameOnlyDefinition], DifferentName) } +module IndexMatch = { + type t = [#FullMatch(int) | #NameMatchOnly(array) | #NoMatch] + let isFullMatch = (t: t) => + switch t { + | #FullMatch(_) => true + | _ => false + } + let isNameOnlyMatch = (t: t) => + switch t { + | #NameMatchOnly(_) => true + | _ => false + } +} + +let match2 = (f: function, fnName: string, args: array) => { + let matchedDefinition = () => + E.A.getIndexBy(f.definitions, r => isFullMatch(matchSingle(r, fnName, args))) |> E.O.fmap(r => + #FullMatch(r) + ) + let getMatchedNameOnlyDefinition = () => { + let nameMatchIndexes = + f.definitions + ->E.A2.fmapi((index, r) => isNameMatchOnly(matchSingle(r, fnName, args)) ? Some(index) : None) + ->E.A.O.concatSomes + switch nameMatchIndexes { + | [] => None + | elements => Some(#NameMatchOnly(elements)) + } + } + + E.A.O.firstSomeFnWithDefault([matchedDefinition, getMatchedNameOnlyDefinition], #NoMatch) +} + +module IndexMatch2 = { + type match = { + fnName: string, + inputIndex: int, + } + type t = [#FullMatch(match) | #NameMatchOnly(array) | #NoMatch] + let makeMatch = (fnName: string, inputIndex: int) => {fnName: fnName, inputIndex: inputIndex} + let isFullMatch = (t: t) => + switch t { + | #FullMatch(_) => true + | _ => false + } + let isNameOnlyMatch = (t: t) => + switch t { + | #NameMatchOnly(_) => true + | _ => false + } +} + +module Registry = { + let findExactMatches = (r: registry, fnName: string, args: array) => { + let functionMatchPairs = r->E.A2.fmap(l => (l, match2(l, fnName, args))) + let getFullMatch = E.A.getBy(functionMatchPairs, ((_, match)) => IndexMatch.isFullMatch(match)) + let fullMatch: option = getFullMatch->E.O.bind(((fn, match)) => + switch match { + | #FullMatch(index) => Some(IndexMatch2.makeMatch(fn.name, index)) + | _ => None + } + ) + fullMatch + } + + let findNameMatches = (r: registry, fnName: string, args: array) => { + let functionMatchPairs = r->E.A2.fmap(l => (l, match2(l, fnName, args))) + let getNameMatches = + functionMatchPairs + ->E.A2.fmap(((fn, match)) => IndexMatch.isNameOnlyMatch(match) ? Some((fn, match)) : None) + ->E.A.O.concatSomes + let matches = + getNameMatches + ->E.A2.fmap(((fn, match)) => + switch match { + | #NameMatchOnly(indexes) => + indexes->E.A2.fmap(index => IndexMatch2.makeMatch(fn.name, index)) + | _ => [] + } + ) + ->Belt.Array.concatMany + E.A.toNoneIfEmpty(matches) + } + + let findMatches = (r: registry, fnName: string, args: array) => { + switch findExactMatches(r, fnName, args) { + | Some(r) => #FullMatch(r) + | None => + switch findNameMatches(r, fnName, args) { + | Some(r) => #NameMatchOnly(r) + | None => #NoMatch + } + } + } + + let fullMatchToDef = (registry: registry, {fnName, inputIndex}: IndexMatch2.match): option< + fnDefinition, + > => + registry + ->E.A.getBy(fn => fn.name === fnName) + ->E.O.bind(fn => E.A.get(fn.definitions, inputIndex)) + + let runDef = (fnDefinition: fnDefinition, args: array) => { + switch matchSingleSameName(fnDefinition, args) { + | Match(_, values) => fnDefinition.run(values) + | _ => Error("Impossible") + } + } + + let matchAndRun = (r: registry, fnName: string, args: array) => { + switch findMatches(r, fnName, args) { + | #FullMatch(m) => fullMatchToDef(r, m)->E.O2.fmap(runDef(_, args)) + | _ => None + } + } +} + let twoNumberInputs = (inputs: array) => switch inputs { | [Number(n1), Number(n2)] => Ok(n1, n2) diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index c3cf855d..06d8d4e9 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -522,6 +522,7 @@ module A = { let unsafe_get = Array.unsafe_get let get = Belt.Array.get let getBy = Belt.Array.getBy + let getIndexBy = Belt.Array.getIndexBy let last = a => get(a, length(a) - 1) let first = get(_, 0) let hasBy = (r, fn) => Belt.Array.getBy(r, fn) |> O.isSome @@ -535,6 +536,7 @@ module A = { let reducei = Belt.Array.reduceWithIndex let isEmpty = r => length(r) < 1 let stableSortBy = Belt.SortArray.stableSortBy + let toNoneIfEmpty = r => isEmpty(r) ? None : Some(r) let toRanges = (a: array<'a>) => switch a |> Belt.Array.length { | 0 @@ -830,6 +832,7 @@ module A = { module A2 = { let fmap = (a, b) => A.fmap(b, a) + let fmapi = (a, b) => A.fmapi(b, a) let joinWith = (a, b) => A.joinWith(b, a) let filter = (a, b) => A.filter(b, a) } From f7f94cbcb141c85269b1e72e4c07892e5a2ca0c4 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Wed, 18 May 2022 16:49:22 -0400 Subject: [PATCH 05/26] First part of cleanup --- .../src/rescript/FunctionRegistry.res | 158 +++++++++--------- 1 file changed, 76 insertions(+), 82 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index 84e5eccb..d7d2986b 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -30,18 +30,6 @@ type function = { type registry = array -module Function = { - let make = (name, definitions): function => { - name: name, - definitions: definitions, - } - let makeDefinition = (name, inputs, run): fnDefinition => { - name: name, - inputs: inputs, - run: run, - } -} - let rec matchInput = (input: itype, r: expressionValue): option => switch (input, r) { | (I_Number, EvNumber(f)) => Some(Number(f)) @@ -67,86 +55,92 @@ let rec matchInput = (input: itype, r: expressionValue): option => | _ => None } -type match = DifferentName | SameNameDifferentArguments(string) | Match(string, array) +module FnDefinition = { + type definitionMatch = + DifferentName | SameNameDifferentArguments(string) | Match(string, array) -let isFullMatch = (match: match) => - switch match { - | Match(_, _) => true - | _ => false + let isFullMatch = (match: definitionMatch) => + switch match { + | Match(_, _) => true + | _ => false + } + + let isNameMatchOnly = (match: definitionMatch) => + switch match { + | SameNameDifferentArguments(_) => true + | _ => false + } + + let matchSingleSameName = (f: fnDefinition, args: array) => { + let inputTypes = f.inputs + if E.A.length(f.inputs) !== E.A.length(args) { + SameNameDifferentArguments(f.name) + } else { + let foo = + E.A.zip(inputTypes, args) + ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) + ->E.A.O.arrSomeToSomeArr + switch foo { + | Some(r) => Match(f.name, r) + | None => SameNameDifferentArguments(f.name) + } + } } -let isNameMatchOnly = (match: match) => - switch match { - | SameNameDifferentArguments(_) => true - | _ => false - } - -let matchSingleSameName = (f: fnDefinition, args: array) => { - let inputTypes = f.inputs - if E.A.length(f.inputs) !== E.A.length(args) { - SameNameDifferentArguments(f.name) - } else { - let foo = - E.A.zip(inputTypes, args) - ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) - ->E.A.O.arrSomeToSomeArr - switch foo { - | Some(r) => Match(f.name, r) - | None => SameNameDifferentArguments(f.name) + let match = (f: fnDefinition, fnName: string, args: array) => { + if f.name !== fnName { + DifferentName + } else { + matchSingleSameName(f, args) } } } -let matchSingle = (f: fnDefinition, fnName: string, args: array) => { - if f.name !== fnName { - DifferentName - } else { - matchSingleSameName(f, args) - } -} - -let match = (f: function, fnName: string, args: array) => { - let matchedDefinition = () => - E.A.getByOpen(f.definitions, r => matchSingle(r, fnName, args), isFullMatch) - let getMatchedNameOnlyDefinition = () => - E.A.getByOpen(f.definitions, r => matchSingle(r, fnName, args), isNameMatchOnly) - E.A.O.firstSomeFnWithDefault([matchedDefinition, getMatchedNameOnlyDefinition], DifferentName) -} - -module IndexMatch = { - type t = [#FullMatch(int) | #NameMatchOnly(array) | #NoMatch] - let isFullMatch = (t: t) => +module Function = { + type match = [#FullMatch(int) | #NameMatchOnly(array) | #NoMatch] + let isFullMatch = (t: match) => switch t { | #FullMatch(_) => true | _ => false } - let isNameOnlyMatch = (t: t) => + let isNameOnlyMatch = (t: match) => switch t { | #NameMatchOnly(_) => true | _ => false } -} - -let match2 = (f: function, fnName: string, args: array) => { - let matchedDefinition = () => - E.A.getIndexBy(f.definitions, r => isFullMatch(matchSingle(r, fnName, args))) |> E.O.fmap(r => - #FullMatch(r) - ) - let getMatchedNameOnlyDefinition = () => { - let nameMatchIndexes = - f.definitions - ->E.A2.fmapi((index, r) => isNameMatchOnly(matchSingle(r, fnName, args)) ? Some(index) : None) - ->E.A.O.concatSomes - switch nameMatchIndexes { - | [] => None - | elements => Some(#NameMatchOnly(elements)) - } + let make = (name, definitions): function => { + name: name, + definitions: definitions, + } + let makeDefinition = (name, inputs, run): fnDefinition => { + name: name, + inputs: inputs, + run: run, } - E.A.O.firstSomeFnWithDefault([matchedDefinition, getMatchedNameOnlyDefinition], #NoMatch) + let match = (f: function, fnName: string, args: array): match => { + let matchedDefinition = () => + E.A.getIndexBy(f.definitions, r => + FnDefinition.isFullMatch(FnDefinition.match(r, fnName, args)) + ) |> E.O.fmap(r => #FullMatch(r)) + let getMatchedNameOnlyDefinition = () => { + let nameMatchIndexes = + f.definitions + ->E.A2.fmapi((index, r) => + FnDefinition.isNameMatchOnly(FnDefinition.match(r, fnName, args)) ? Some(index) : None + ) + ->E.A.O.concatSomes + switch nameMatchIndexes { + | [] => None + | elements => Some(#NameMatchOnly(elements)) + } + } + + E.A.O.firstSomeFnWithDefault([matchedDefinition, getMatchedNameOnlyDefinition], #NoMatch) + } } -module IndexMatch2 = { +module RegistryMatch = { type match = { fnName: string, inputIndex: int, @@ -167,11 +161,11 @@ module IndexMatch2 = { module Registry = { let findExactMatches = (r: registry, fnName: string, args: array) => { - let functionMatchPairs = r->E.A2.fmap(l => (l, match2(l, fnName, args))) - let getFullMatch = E.A.getBy(functionMatchPairs, ((_, match)) => IndexMatch.isFullMatch(match)) - let fullMatch: option = getFullMatch->E.O.bind(((fn, match)) => + let functionMatchPairs = r->E.A2.fmap(l => (l, Function.match(l, fnName, args))) + let getFullMatch = E.A.getBy(functionMatchPairs, ((_, match)) => Function.isFullMatch(match)) + let fullMatch: option = getFullMatch->E.O.bind(((fn, match)) => switch match { - | #FullMatch(index) => Some(IndexMatch2.makeMatch(fn.name, index)) + | #FullMatch(index) => Some(RegistryMatch.makeMatch(fn.name, index)) | _ => None } ) @@ -179,17 +173,17 @@ module Registry = { } let findNameMatches = (r: registry, fnName: string, args: array) => { - let functionMatchPairs = r->E.A2.fmap(l => (l, match2(l, fnName, args))) + let functionMatchPairs = r->E.A2.fmap(l => (l, Function.match(l, fnName, args))) let getNameMatches = functionMatchPairs - ->E.A2.fmap(((fn, match)) => IndexMatch.isNameOnlyMatch(match) ? Some((fn, match)) : None) + ->E.A2.fmap(((fn, match)) => Function.isNameOnlyMatch(match) ? Some((fn, match)) : None) ->E.A.O.concatSomes let matches = getNameMatches ->E.A2.fmap(((fn, match)) => switch match { | #NameMatchOnly(indexes) => - indexes->E.A2.fmap(index => IndexMatch2.makeMatch(fn.name, index)) + indexes->E.A2.fmap(index => RegistryMatch.makeMatch(fn.name, index)) | _ => [] } ) @@ -208,7 +202,7 @@ module Registry = { } } - let fullMatchToDef = (registry: registry, {fnName, inputIndex}: IndexMatch2.match): option< + let fullMatchToDef = (registry: registry, {fnName, inputIndex}: RegistryMatch.match): option< fnDefinition, > => registry @@ -216,7 +210,7 @@ module Registry = { ->E.O.bind(fn => E.A.get(fn.definitions, inputIndex)) let runDef = (fnDefinition: fnDefinition, args: array) => { - switch matchSingleSameName(fnDefinition, args) { + switch FnDefinition.matchSingleSameName(fnDefinition, args) { | Match(_, values) => fnDefinition.run(values) | _ => Error("Impossible") } From b67c90eb0627ae0ad8c301ff067e4bb8d0f4fb8e Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Wed, 18 May 2022 17:27:36 -0400 Subject: [PATCH 06/26] Cleaned up FunctionRegistry to use Match type --- .../src/rescript/FunctionRegistry.res | 129 ++++++++++-------- 1 file changed, 69 insertions(+), 60 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index d7d2986b..4cd20e87 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -55,59 +55,80 @@ let rec matchInput = (input: itype, r: expressionValue): option => | _ => None } -module FnDefinition = { - type definitionMatch = - DifferentName | SameNameDifferentArguments(string) | Match(string, array) +module MatchSimple = { + type t = DifferentName | SameNameDifferentArguments | FullMatch - let isFullMatch = (match: definitionMatch) => + let isFullMatch = (match: t) => switch match { - | Match(_, _) => true + | FullMatch => true | _ => false } - let isNameMatchOnly = (match: definitionMatch) => + let isNameMatchOnly = (match: t) => + switch match { + | SameNameDifferentArguments => true + | _ => false + } +} + +module Match = { + type t<'a, 'b> = DifferentName | SameNameDifferentArguments('a) | FullMatch('b) + + let isFullMatch = (match: t<'a, 'b>): bool => + switch match { + | FullMatch(_) => true + | _ => false + } + + let isNameMatchOnly = (match: t<'a, 'b>) => switch match { | SameNameDifferentArguments(_) => true | _ => false } +} - let matchSingleSameName = (f: fnDefinition, args: array) => { +module FnDefinition = { + type definitionMatch = MatchSimple.t + + let getArgValues = (f: fnDefinition, args: array): option> => { let inputTypes = f.inputs if E.A.length(f.inputs) !== E.A.length(args) { - SameNameDifferentArguments(f.name) + None } else { - let foo = - E.A.zip(inputTypes, args) - ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) - ->E.A.O.arrSomeToSomeArr - switch foo { - | Some(r) => Match(f.name, r) - | None => SameNameDifferentArguments(f.name) - } + E.A.zip(inputTypes, args) + ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) + ->E.A.O.arrSomeToSomeArr + } + } + + let matchAssumingSameName = (f: fnDefinition, args: array) => { + switch getArgValues(f, args) { + | Some(_) => MatchSimple.FullMatch + | None => MatchSimple.SameNameDifferentArguments } } let match = (f: fnDefinition, fnName: string, args: array) => { if f.name !== fnName { - DifferentName + MatchSimple.DifferentName } else { - matchSingleSameName(f, args) + matchAssumingSameName(f, args) + } + } + + let run = (f: fnDefinition, args: array) => { + let argValues = getArgValues(f, args) + switch argValues { + | Some(values) => f.run(values) + | None => Error("Impossible") } } } module Function = { - type match = [#FullMatch(int) | #NameMatchOnly(array) | #NoMatch] - let isFullMatch = (t: match) => - switch t { - | #FullMatch(_) => true - | _ => false - } - let isNameOnlyMatch = (t: match) => - switch t { - | #NameMatchOnly(_) => true - | _ => false - } + type definitionId = int + type match = Match.t, definitionId> + let make = (name, definitions): function => { name: name, definitions: definitions, @@ -121,22 +142,25 @@ module Function = { let match = (f: function, fnName: string, args: array): match => { let matchedDefinition = () => E.A.getIndexBy(f.definitions, r => - FnDefinition.isFullMatch(FnDefinition.match(r, fnName, args)) - ) |> E.O.fmap(r => #FullMatch(r)) + MatchSimple.isFullMatch(FnDefinition.match(r, fnName, args)) + ) |> E.O.fmap(r => Match.FullMatch(r)) let getMatchedNameOnlyDefinition = () => { let nameMatchIndexes = f.definitions ->E.A2.fmapi((index, r) => - FnDefinition.isNameMatchOnly(FnDefinition.match(r, fnName, args)) ? Some(index) : None + MatchSimple.isNameMatchOnly(FnDefinition.match(r, fnName, args)) ? Some(index) : None ) ->E.A.O.concatSomes switch nameMatchIndexes { | [] => None - | elements => Some(#NameMatchOnly(elements)) + | elements => Some(Match.SameNameDifferentArguments(elements)) } } - E.A.O.firstSomeFnWithDefault([matchedDefinition, getMatchedNameOnlyDefinition], #NoMatch) + E.A.O.firstSomeFnWithDefault( + [matchedDefinition, getMatchedNameOnlyDefinition], + Match.DifferentName, + ) } } @@ -145,27 +169,19 @@ module RegistryMatch = { fnName: string, inputIndex: int, } - type t = [#FullMatch(match) | #NameMatchOnly(array) | #NoMatch] + type t = Match.t, match> let makeMatch = (fnName: string, inputIndex: int) => {fnName: fnName, inputIndex: inputIndex} - let isFullMatch = (t: t) => - switch t { - | #FullMatch(_) => true - | _ => false - } - let isNameOnlyMatch = (t: t) => - switch t { - | #NameMatchOnly(_) => true - | _ => false - } } module Registry = { let findExactMatches = (r: registry, fnName: string, args: array) => { let functionMatchPairs = r->E.A2.fmap(l => (l, Function.match(l, fnName, args))) - let getFullMatch = E.A.getBy(functionMatchPairs, ((_, match)) => Function.isFullMatch(match)) + let getFullMatch = E.A.getBy(functionMatchPairs, ((_, match: Function.match)) => + Match.isFullMatch(match) + ) let fullMatch: option = getFullMatch->E.O.bind(((fn, match)) => switch match { - | #FullMatch(index) => Some(RegistryMatch.makeMatch(fn.name, index)) + | FullMatch(index) => Some(RegistryMatch.makeMatch(fn.name, index)) | _ => None } ) @@ -176,13 +192,13 @@ module Registry = { let functionMatchPairs = r->E.A2.fmap(l => (l, Function.match(l, fnName, args))) let getNameMatches = functionMatchPairs - ->E.A2.fmap(((fn, match)) => Function.isNameOnlyMatch(match) ? Some((fn, match)) : None) + ->E.A2.fmap(((fn, match)) => Match.isNameMatchOnly(match) ? Some((fn, match)) : None) ->E.A.O.concatSomes let matches = getNameMatches ->E.A2.fmap(((fn, match)) => switch match { - | #NameMatchOnly(indexes) => + | SameNameDifferentArguments(indexes) => indexes->E.A2.fmap(index => RegistryMatch.makeMatch(fn.name, index)) | _ => [] } @@ -193,11 +209,11 @@ module Registry = { let findMatches = (r: registry, fnName: string, args: array) => { switch findExactMatches(r, fnName, args) { - | Some(r) => #FullMatch(r) + | Some(r) => Match.FullMatch(r) | None => switch findNameMatches(r, fnName, args) { - | Some(r) => #NameMatchOnly(r) - | None => #NoMatch + | Some(r) => Match.SameNameDifferentArguments(r) + | None => Match.DifferentName } } } @@ -209,16 +225,9 @@ module Registry = { ->E.A.getBy(fn => fn.name === fnName) ->E.O.bind(fn => E.A.get(fn.definitions, inputIndex)) - let runDef = (fnDefinition: fnDefinition, args: array) => { - switch FnDefinition.matchSingleSameName(fnDefinition, args) { - | Match(_, values) => fnDefinition.run(values) - | _ => Error("Impossible") - } - } - let matchAndRun = (r: registry, fnName: string, args: array) => { switch findMatches(r, fnName, args) { - | #FullMatch(m) => fullMatchToDef(r, m)->E.O2.fmap(runDef(_, args)) + | Match.FullMatch(m) => fullMatchToDef(r, m)->E.O2.fmap(FnDefinition.run(_, args)) | _ => None } } From 88ae0e25b410d0d697000b0901edec432beb0b83 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Wed, 18 May 2022 18:25:32 -0400 Subject: [PATCH 07/26] Simple experiment of it working --- .../src/rescript/FunctionRegistry.res | 20 +++++++++++++----- .../ReducerInterface_GenericDistribution.res | 21 +++++++++++++++---- .../squiggle-lang/src/rescript/Utility/E.res | 8 +++++++ 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index 4cd20e87..f0d142c1 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -95,9 +95,13 @@ module FnDefinition = { if E.A.length(f.inputs) !== E.A.length(args) { None } else { - E.A.zip(inputTypes, args) + let foo = E.A.zip(inputTypes, args) + ->(e => {Js.log2("Here", e); e}) ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) - ->E.A.O.arrSomeToSomeArr + ->(e => {Js.log2("Here2", e); e}) + ->E.A.O.openIfAllSome + ->(e => {Js.log2("Here3", e); e}); + foo } } @@ -117,7 +121,9 @@ module FnDefinition = { } let run = (f: fnDefinition, args: array) => { + Js.log3("Run", f, args) let argValues = getArgValues(f, args) + Js.log2("RunArgValues", argValues) switch argValues { | Some(values) => f.run(values) | None => Error("Impossible") @@ -227,17 +233,21 @@ module Registry = { let matchAndRun = (r: registry, fnName: string, args: array) => { switch findMatches(r, fnName, args) { - | Match.FullMatch(m) => fullMatchToDef(r, m)->E.O2.fmap(FnDefinition.run(_, args)) + | Match.FullMatch(m) => fullMatchToDef(r, m)->E.O2.fmap(r => { + FnDefinition.run(r, args) + }) | _ => None } } } -let twoNumberInputs = (inputs: array) => +let twoNumberInputs = (inputs: array) =>{ + Js.log2("HII",inputs); switch inputs { | [Number(n1), Number(n2)] => Ok(n1, n2) | _ => Error("Wrong inputs / Logically impossible") } +} let twoNumberInputsRecord = (v1, v2, inputs: array) => switch inputs { @@ -270,7 +280,7 @@ let normal = Function.make( ), Function.makeDefinition("normal", [I_Record([("p5", I_Numeric), ("p95", I_Numeric)])], inputs => twoNumberInputsRecord("p5", "p95", inputs)->E.R.bind(((mean, stdev)) => - meanStdev(mean, stdev) + Ok(p5and95(mean, stdev)) ) ), ], diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 0f29f9db..824b5b32 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -227,8 +227,8 @@ let dispatchToGenericOutput = ( | ("delta", [EvNumber(f)]) => SymbolicDist.Float.makeSafe(f)->SymbolicConstructors.symbolicResultToOutput | ( - ("normal" - | "uniform" + ( + "uniform" | "beta" | "lognormal" | "cauchy" @@ -386,6 +386,19 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result< | GenDistError(err) => Error(REDistributionError(err)) } -let dispatch = (call, environment) => { - dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue) +let registered = [FunctionRegistry.normal] + +let tryRegistry = (call:ExpressionValue.functionCall) => { + let (fnName, args) = call; + let response = FunctionRegistry.Registry.matchAndRun(registered, fnName, args) + let foo = response -> E.O2.fmap(r => r->E.R2.errMap(s => Reducer_ErrorValue.RETodo(s))) + foo +} + +let dispatch = (call:ExpressionValue.functionCall, environment) => { + let regularDispatch = dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue) + switch(regularDispatch){ + | Some(x) => Some(x) + | None => tryRegistry(call) + } } diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 06d8d4e9..b096303d 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -646,6 +646,14 @@ module A = { O.flatten(getByOpen(r, l => l(), O.isSome)) let firstSomeFnWithDefault = (r, default) => firstSomeFn(r)->O2.default(default) + + let openIfAllSome = (optionals: array>): option> => { + if all(O.isSome, optionals) { + Some(optionals |> fmap(O.toExn("Warning: This should not have happened"))) + } else { + None + } + } } module R = { From 76bbfb2ef18a6b71a5ae8411fe3e474e37d7f79d Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Wed, 18 May 2022 18:42:28 -0400 Subject: [PATCH 08/26] Added lognormal fn definitions --- .../src/rescript/FunctionRegistry.res | 49 +++++++++++++------ .../ReducerInterface_GenericDistribution.res | 22 ++++----- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index f0d142c1..d01d5736 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -95,13 +95,9 @@ module FnDefinition = { if E.A.length(f.inputs) !== E.A.length(args) { None } else { - let foo = E.A.zip(inputTypes, args) - ->(e => {Js.log2("Here", e); e}) + E.A.zip(inputTypes, args) ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) - ->(e => {Js.log2("Here2", e); e}) ->E.A.O.openIfAllSome - ->(e => {Js.log2("Here3", e); e}); - foo } } @@ -121,9 +117,7 @@ module FnDefinition = { } let run = (f: fnDefinition, args: array) => { - Js.log3("Run", f, args) let argValues = getArgValues(f, args) - Js.log2("RunArgValues", argValues) switch argValues { | Some(values) => f.run(values) | None => Error("Impossible") @@ -233,16 +227,16 @@ module Registry = { let matchAndRun = (r: registry, fnName: string, args: array) => { switch findMatches(r, fnName, args) { - | Match.FullMatch(m) => fullMatchToDef(r, m)->E.O2.fmap(r => { + | Match.FullMatch(m) => + fullMatchToDef(r, m)->E.O2.fmap(r => { FnDefinition.run(r, args) - }) + }) | _ => None } } } -let twoNumberInputs = (inputs: array) =>{ - Js.log2("HII",inputs); +let twoNumberInputs = (inputs: array) => { switch inputs { | [Number(n1), Number(n2)] => Ok(n1, n2) | _ => Error("Wrong inputs / Logically impossible") @@ -279,9 +273,36 @@ let normal = Function.make( ), ), Function.makeDefinition("normal", [I_Record([("p5", I_Numeric), ("p95", I_Numeric)])], inputs => - twoNumberInputsRecord("p5", "p95", inputs)->E.R.bind(((mean, stdev)) => - Ok(p5and95(mean, stdev)) - ) + twoNumberInputsRecord("p5", "p95", inputs)->E.R.bind(((v1, v2)) => Ok(p5and95(v1, v2))) ), ], ) + +let logNormal = Function.make( + "Lognormal", + [ + Function.makeDefinition("lognormal", [I_Numeric, I_Numeric], inputs => + twoNumberInputs(inputs)->E.R.bind(((mu, sigma)) => + SymbolicDist.Lognormal.make(mu, sigma)->E.R2.fmap(contain) + ) + ), + Function.makeDefinition( + "lognormal", + [I_Record([("p5", I_Numeric), ("p95", I_Numeric)])], + inputs => + twoNumberInputsRecord("p5", "p95", inputs)->E.R.bind(((p5, p95)) => Ok( + contain(SymbolicDist.Lognormal.from90PercentCI(p5, p95)), + )), + ), + Function.makeDefinition( + "lognormal", + [I_Record([("mean", I_Numeric), ("stdev", I_Numeric)])], + inputs => + twoNumberInputsRecord("mean", "stdev", inputs)->E.R.bind(((mean, stdev)) => + SymbolicDist.Lognormal.fromMeanAndStdev(mean, stdev)->E.R2.fmap(contain) + ), + ), + ], +) + +let allFunctions = [normal, logNormal] diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 824b5b32..d2e9b65e 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -227,8 +227,7 @@ let dispatchToGenericOutput = ( | ("delta", [EvNumber(f)]) => SymbolicDist.Float.makeSafe(f)->SymbolicConstructors.symbolicResultToOutput | ( - ( - "uniform" + ("uniform" | "beta" | "lognormal" | "cauchy" @@ -386,19 +385,20 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result< | GenDistError(err) => Error(REDistributionError(err)) } -let registered = [FunctionRegistry.normal] +let registered = FunctionRegistry.allFunctions -let tryRegistry = (call:ExpressionValue.functionCall) => { - let (fnName, args) = call; +let tryRegistry = (call: ExpressionValue.functionCall) => { + let (fnName, args) = call let response = FunctionRegistry.Registry.matchAndRun(registered, fnName, args) - let foo = response -> E.O2.fmap(r => r->E.R2.errMap(s => Reducer_ErrorValue.RETodo(s))) + let foo = response->E.O2.fmap(r => r->E.R2.errMap(s => Reducer_ErrorValue.RETodo(s))) foo } -let dispatch = (call:ExpressionValue.functionCall, environment) => { - let regularDispatch = dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue) - switch(regularDispatch){ - | Some(x) => Some(x) - | None => tryRegistry(call) +let dispatch = (call: ExpressionValue.functionCall, environment) => { + let regularDispatch = + dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue) + switch regularDispatch { + | Some(x) => Some(x) + | None => tryRegistry(call) } } From 69d962ce753dfdef944d834cc7fa99b81a82053f Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Wed, 18 May 2022 19:10:34 -0400 Subject: [PATCH 09/26] Wip, working on allowing distributions in normal --- .../squiggle-lang/src/rescript/FunctionRegistry.res | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index d01d5736..7a74ed0c 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -258,12 +258,24 @@ let p5and95 = (p5, p95) => contain(SymbolicDist.Normal.from90PercentCI(p5, p95)) let convertTwoInputs = (inputs: array): result => twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) +// let twoDistOrStdev = (a1:distOrNumber, a2:distOrNumber, fn) => { +// switch (a1, a2) { +// | (Number(a1), Number(a2)) => fn(a1, a2) +// | (Dist(a1), Number(a2)) => toSampleSetDist(a1, 1000)->sampleMap(r => fn(r, a2) |> sample) +// | (Number(a1), Dist(a2)) => toSampleSetDist(a2, 1000)->sampleMap(r => fn(a1, r) |> sample) +// | (Dist(a1), Dist(a2)) => SampleSetDist.map2(a1, a2, (m, s) => fn(m, s) |> sample) +// } +// } + let normal = Function.make( "Normal", [ Function.makeDefinition("normal", [I_Numeric, I_Numeric], inputs => twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) ), + Function.makeDefinition("normal", [I_DistOrNumber, I_DistOrNumber], inputs => + twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) + ), Function.makeDefinition( "normal", [I_Record([("mean", I_Numeric), ("stdev", I_Numeric)])], From 50a5ef2498256a9c7a56bfe55328a5e9f4238860 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 19 May 2022 09:25:34 -0400 Subject: [PATCH 10/26] Touchups for FunctionRegistry distTwo --- .../rescript/Distributions/GenericDist.res | 3 + .../rescript/Distributions/GenericDist.resi | 1 + .../src/rescript/FunctionRegistry.res | 83 +++++++++++++++---- .../src/rescript/Utility/Operation.res | 2 + 4 files changed, 73 insertions(+), 16 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res index 1df10240..dc50833e 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res @@ -24,6 +24,7 @@ let isSymbolic = (t: t) => | _ => false } + let sampleN = (t: t, n) => switch t { | PointSet(r) => PointSetDist.sampleNRendered(n, r) @@ -31,6 +32,8 @@ let sampleN = (t: t, n) => | SampleSet(r) => SampleSetDist.sampleN(r, n) } +let sample = (t: t) => sampleN(t, 1) -> E.A.first |> E.O.toExn("Should not have happened") + let toSampleSetDist = (t: t, n) => SampleSetDist.make(sampleN(t, n))->E.R2.errMap(DistributionTypes.Error.sampleErrorToDistErr) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist.resi b/packages/squiggle-lang/src/rescript/Distributions/GenericDist.resi index 79fb54ab..fd9afa58 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist.resi +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist.resi @@ -6,6 +6,7 @@ type scaleMultiplyFn = (t, float) => result type pointwiseAddFn = (t, t) => result let sampleN: (t, int) => array +let sample: t => float let toSampleSetDist: (t, int) => Belt.Result.t diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index 7a74ed0c..df04cef9 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -34,6 +34,7 @@ let rec matchInput = (input: itype, r: expressionValue): option => switch (input, r) { | (I_Number, EvNumber(f)) => Some(Number(f)) | (I_DistOrNumber, EvNumber(f)) => Some(DistOrNumber(Number(f))) + | (I_DistOrNumber, EvDistribution(Symbolic(#Float(f)))) => Some(DistOrNumber(Number(f))) | (I_DistOrNumber, EvDistribution(f)) => Some(DistOrNumber(Dist(f))) | (I_Numeric, EvNumber(f)) => Some(Number(f)) | (I_Numeric, EvDistribution(Symbolic(#Float(f)))) => Some(Number(f)) @@ -236,17 +237,19 @@ module Registry = { } } +let impossibleError = "Wrong inputs / Logically impossible" + let twoNumberInputs = (inputs: array) => { switch inputs { | [Number(n1), Number(n2)] => Ok(n1, n2) - | _ => Error("Wrong inputs / Logically impossible") + | _ => Error(impossibleError) } } let twoNumberInputsRecord = (v1, v2, inputs: array) => switch inputs { | [Record([(name1, n1), (name2, n2)])] if name1 == v1 && name2 == v2 => twoNumberInputs([n1, n2]) - | _ => Error("Wrong inputs / Logically impossible") + | _ => Error(impossibleError) } let contain = r => ReducerInterface_ExpressionValue.EvDistribution(Symbolic(r)) @@ -258,24 +261,72 @@ let p5and95 = (p5, p95) => contain(SymbolicDist.Normal.from90PercentCI(p5, p95)) let convertTwoInputs = (inputs: array): result => twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) -// let twoDistOrStdev = (a1:distOrNumber, a2:distOrNumber, fn) => { -// switch (a1, a2) { -// | (Number(a1), Number(a2)) => fn(a1, a2) -// | (Dist(a1), Number(a2)) => toSampleSetDist(a1, 1000)->sampleMap(r => fn(r, a2) |> sample) -// | (Number(a1), Dist(a2)) => toSampleSetDist(a2, 1000)->sampleMap(r => fn(a1, r) |> sample) -// | (Dist(a1), Dist(a2)) => SampleSetDist.map2(a1, a2, (m, s) => fn(m, s) |> sample) -// } -// } +let twoDistOrStdev = (a1: value, a2: value) => { + switch (a1, a2) { + | (DistOrNumber(a1), DistOrNumber(a2)) => Ok(a1, a2) + | _ => Error(impossibleError) + } +} + +let distTwo = ( + ~fn: (float, float) => result, + a1: value, + a2: value, +) => { + let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) + let sampleSetToExpressionValue = ( + b: Belt.Result.t, + ) => + switch b { + | Ok(r) => Ok(ReducerInterface_ExpressionValue.EvDistribution(SampleSet(r))) + | Error(d) => Error(DistributionTypes.Error.toString(d)) + } + + let mapFnResult = r => + switch r { + | Ok(r) => Ok(GenericDist.sample(r)) + | Error(r) => Error(Operation.Other(r)) + } + + let singleVarSample = (a, fn) => { + let sampleSetResult = + toSampleSet(a) |> E.R2.bind(dist => + SampleSetDist.samplesMap( + ~fn=f => fn(f)->mapFnResult, + dist, + )->E.R2.errMap(r => DistributionTypes.SampleSetError(r)) + ) + sampleSetResult->sampleSetToExpressionValue + } + + switch (a1, a2) { + | (DistOrNumber(Number(a1)), DistOrNumber(Number(a2))) => + fn(a1, a2)->E.R2.fmap(r => ReducerInterface_ExpressionValue.EvDistribution(r)) + | (DistOrNumber(Dist(a1)), DistOrNumber(Number(a2))) => singleVarSample(a1, r => fn(r, a2)) + | (DistOrNumber(Number(a1)), DistOrNumber(Dist(a2))) => singleVarSample(a2, r => fn(a1, r)) + | (DistOrNumber(Dist(a1)), DistOrNumber(Dist(a2))) => { + let altFn = (a, b) => fn(a, b)->mapFnResult + let sampleSetResult = + E.R.merge(toSampleSet(a1), toSampleSet(a2)) + ->E.R2.errMap(DistributionTypes.Error.toString) + ->E.R.bind(((t1, t2)) => { + SampleSetDist.map2(~fn=altFn, ~t1, ~t2)->E.R2.errMap(Operation.Error.toString) + }) + ->E.R2.errMap(r => DistributionTypes.OtherError(r)) + sampleSetResult->sampleSetToExpressionValue + } + | _ => Error(impossibleError) + } +} let normal = Function.make( "Normal", [ - Function.makeDefinition("normal", [I_Numeric, I_Numeric], inputs => - twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) - ), - Function.makeDefinition("normal", [I_DistOrNumber, I_DistOrNumber], inputs => - twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) - ), + Function.makeDefinition("normal", [I_DistOrNumber, I_DistOrNumber], inputs => { + let combine = (a1: float, a2: float) => + SymbolicDist.Normal.make(a1, a2)->E.R2.fmap(r => DistributionTypes.Symbolic(r)) + distTwo(~fn=combine, inputs[0], inputs[1]) + }), Function.makeDefinition( "normal", [I_Record([("mean", I_Numeric), ("stdev", I_Numeric)])], diff --git a/packages/squiggle-lang/src/rescript/Utility/Operation.res b/packages/squiggle-lang/src/rescript/Utility/Operation.res index 7972b2fa..6476850d 100644 --- a/packages/squiggle-lang/src/rescript/Utility/Operation.res +++ b/packages/squiggle-lang/src/rescript/Utility/Operation.res @@ -58,6 +58,7 @@ type operationError = | SampleMapNeedsNtoNFunction | PdfInvalidError | NotYetImplemented // should be removed when `klDivergence` for mixed and discrete is implemented. + | Other(string) @genType module Error = { @@ -73,6 +74,7 @@ module Error = { | SampleMapNeedsNtoNFunction => "SampleMap needs a function that converts a number to a number" | PdfInvalidError => "This Pdf is invalid" | NotYetImplemented => "This pathway is not yet implemented" + | Other(t) => t } } From 58f1789cfed22e596f6bfe11b151ac8c60a3e69e Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 19 May 2022 15:12:36 -0400 Subject: [PATCH 11/26] Refactored Normal and Lognormal functions --- .../src/rescript/FunctionRegistry.res | 209 +++++++++++------- 1 file changed, 125 insertions(+), 84 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index df04cef9..a1138129 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -130,11 +130,12 @@ module Function = { type definitionId = int type match = Match.t, definitionId> - let make = (name, definitions): function => { + let make = (~name, ~definitions): function => { name: name, definitions: definitions, } - let makeDefinition = (name, inputs, run): fnDefinition => { + + let makeDefinition = (~name, ~inputs, ~run): fnDefinition => { name: name, inputs: inputs, run: run, @@ -239,39 +240,50 @@ module Registry = { let impossibleError = "Wrong inputs / Logically impossible" -let twoNumberInputs = (inputs: array) => { - switch inputs { - | [Number(n1), Number(n2)] => Ok(n1, n2) - | _ => Error(impossibleError) +module Prepare = { + let twoNumberInputs = (inputs: array) => { + switch inputs { + | [Number(n1), Number(n2)] => Ok(n1, n2) + | _ => Error(impossibleError) + } } + + let twoDistOrNumber = (values: array) => { + switch values { + | [DistOrNumber(a1), DistOrNumber(a2)] => Ok(a1, a2) + | _ => Error(impossibleError) + } + } + + let twoNumberInputsRecord = (v1: string, v2: string, inputs: array) => + switch inputs { + | [Record([(name1, n1), (name2, n2)])] if name1 == v1 && name2 == v2 => + twoNumberInputs([n1, n2]) + | _ => Error(impossibleError) + } + + let twoNumberInputsRecord2 = (inputs: array) => + switch inputs { + | [Record([(_, n1), (_, n2)])] => twoNumberInputs([n1, n2]) + | _ => Error(impossibleError) + } + + let twoNumberInputsRecord3 = (inputs: array) => + switch inputs { + | [Record([(_, n1), (_, n2)])] => Ok([n1, n2]) + | _ => Error(impossibleError) + } } -let twoNumberInputsRecord = (v1, v2, inputs: array) => - switch inputs { - | [Record([(name1, n1), (name2, n2)])] if name1 == v1 && name2 == v2 => twoNumberInputs([n1, n2]) - | _ => Error(impossibleError) - } - -let contain = r => ReducerInterface_ExpressionValue.EvDistribution(Symbolic(r)) - -let meanStdev = (mean, stdev) => SymbolicDist.Normal.make(mean, stdev)->E.R2.fmap(contain) - -let p5and95 = (p5, p95) => contain(SymbolicDist.Normal.from90PercentCI(p5, p95)) - -let convertTwoInputs = (inputs: array): result => - twoNumberInputs(inputs)->E.R.bind(((mean, stdev)) => meanStdev(mean, stdev)) - -let twoDistOrStdev = (a1: value, a2: value) => { - switch (a1, a2) { - | (DistOrNumber(a1), DistOrNumber(a2)) => Ok(a1, a2) - | _ => Error(impossibleError) - } +module Wrappers = { + let symbolic = r => DistributionTypes.Symbolic(r) + let evDistribution = r => ReducerInterface_ExpressionValue.EvDistribution(r) + let symbolicEvDistribution = r => r->Symbolic->evDistribution } -let distTwo = ( +let twoDistsOrNumbers = ( ~fn: (float, float) => result, - a1: value, - a2: value, + ~values: (distOrNumber, distOrNumber), ) => { let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) let sampleSetToExpressionValue = ( @@ -299,12 +311,11 @@ let distTwo = ( sampleSetResult->sampleSetToExpressionValue } - switch (a1, a2) { - | (DistOrNumber(Number(a1)), DistOrNumber(Number(a2))) => - fn(a1, a2)->E.R2.fmap(r => ReducerInterface_ExpressionValue.EvDistribution(r)) - | (DistOrNumber(Dist(a1)), DistOrNumber(Number(a2))) => singleVarSample(a1, r => fn(r, a2)) - | (DistOrNumber(Number(a1)), DistOrNumber(Dist(a2))) => singleVarSample(a2, r => fn(a1, r)) - | (DistOrNumber(Dist(a1)), DistOrNumber(Dist(a2))) => { + switch values { + | (Number(a1), Number(a2)) => fn(a1, a2)->E.R2.fmap(Wrappers.evDistribution) + | (Dist(a1), Number(a2)) => singleVarSample(a1, r => fn(r, a2)) + | (Number(a1), Dist(a2)) => singleVarSample(a2, r => fn(a1, r)) + | (Dist(a1), Dist(a2)) => { let altFn = (a, b) => fn(a, b)->mapFnResult let sampleSetResult = E.R.merge(toSampleSet(a1), toSampleSet(a2)) @@ -315,57 +326,87 @@ let distTwo = ( ->E.R2.errMap(r => DistributionTypes.OtherError(r)) sampleSetResult->sampleSetToExpressionValue } - | _ => Error(impossibleError) } } -let normal = Function.make( - "Normal", - [ - Function.makeDefinition("normal", [I_DistOrNumber, I_DistOrNumber], inputs => { - let combine = (a1: float, a2: float) => - SymbolicDist.Normal.make(a1, a2)->E.R2.fmap(r => DistributionTypes.Symbolic(r)) - distTwo(~fn=combine, inputs[0], inputs[1]) - }), - Function.makeDefinition( - "normal", - [I_Record([("mean", I_Numeric), ("stdev", I_Numeric)])], - inputs => - twoNumberInputsRecord("mean", "stdev", inputs)->E.R.bind(((mean, stdev)) => - meanStdev(mean, stdev) - ), - ), - Function.makeDefinition("normal", [I_Record([("p5", I_Numeric), ("p95", I_Numeric)])], inputs => - twoNumberInputsRecord("p5", "p95", inputs)->E.R.bind(((v1, v2)) => Ok(p5and95(v1, v2))) - ), - ], -) +module NormalFn = { + let fnName = "normal" + let twoFloatsToSymoblic = (a1: float, a2: float) => + SymbolicDist.Normal.make(a1, a2)->E.R2.fmap(Wrappers.symbolic) + let twoFloatsToSymbolic90P = (a1: float, a2: float) => + SymbolicDist.Normal.from90PercentCI(a1, a2)->Wrappers.symbolic->Ok -let logNormal = Function.make( - "Lognormal", - [ - Function.makeDefinition("lognormal", [I_Numeric, I_Numeric], inputs => - twoNumberInputs(inputs)->E.R.bind(((mu, sigma)) => - SymbolicDist.Lognormal.make(mu, sigma)->E.R2.fmap(contain) - ) - ), - Function.makeDefinition( - "lognormal", - [I_Record([("p5", I_Numeric), ("p95", I_Numeric)])], - inputs => - twoNumberInputsRecord("p5", "p95", inputs)->E.R.bind(((p5, p95)) => Ok( - contain(SymbolicDist.Lognormal.from90PercentCI(p5, p95)), - )), - ), - Function.makeDefinition( - "lognormal", - [I_Record([("mean", I_Numeric), ("stdev", I_Numeric)])], - inputs => - twoNumberInputsRecord("mean", "stdev", inputs)->E.R.bind(((mean, stdev)) => - SymbolicDist.Lognormal.fromMeanAndStdev(mean, stdev)->E.R2.fmap(contain) - ), - ), - ], -) + let toFn = Function.make( + ~name="Normal", + ~definitions=[ + Function.makeDefinition( + ~name=fnName, + ~inputs=[I_DistOrNumber, I_DistOrNumber], + ~run=inputs => { + inputs + ->Prepare.twoDistOrNumber + ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToSymoblic, ~values=_)) + }, + ), + Function.makeDefinition( + ~name=fnName, + ~inputs=[I_Record([("mean", I_DistOrNumber), ("stdev", I_DistOrNumber)])], + ~run=inputs => + inputs + ->Prepare.twoNumberInputsRecord3 + ->E.R.bind(Prepare.twoDistOrNumber) + ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToSymoblic, ~values=_)), + ), + Function.makeDefinition( + ~name=fnName, + ~inputs=[I_Record([("p5", I_DistOrNumber), ("p95", I_DistOrNumber)])], + ~run=inputs => + inputs + ->Prepare.twoNumberInputsRecord3 + ->E.R.bind(Prepare.twoDistOrNumber) + ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToSymbolic90P, ~values=_)), + ), + ], + ) +} -let allFunctions = [normal, logNormal] +module LognormalFn = { + let fnName = "lognormal" + let twoFloatsToSymoblic = (a1, a2) => + SymbolicDist.Lognormal.make(a1, a2)->E.R2.fmap(Wrappers.symbolic) + let twoFloatsToSymbolic90P = (a1, a2) => + SymbolicDist.Lognormal.from90PercentCI(a1, a2)->Wrappers.symbolic->Ok + let twoFloatsToMeanStdev = (a1, a2) => + SymbolicDist.Lognormal.fromMeanAndStdev(a1, a2)->E.R2.fmap(Wrappers.symbolic) + + let toFn = Function.make( + ~name="Lognormal", + ~definitions=[ + Function.makeDefinition(~name=fnName, ~inputs=[I_DistOrNumber, I_DistOrNumber], ~run=inputs => + inputs + ->Prepare.twoDistOrNumber + ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToSymoblic, ~values=_)) + ), + Function.makeDefinition( + ~name=fnName, + ~inputs=[I_Record([("p5", I_DistOrNumber), ("p95", I_DistOrNumber)])], + ~run=inputs => + inputs + ->Prepare.twoNumberInputsRecord3 + ->E.R.bind(Prepare.twoDistOrNumber) + ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToSymbolic90P, ~values=_)), + ), + Function.makeDefinition( + ~name=fnName, + ~inputs=[I_Record([("mean", I_DistOrNumber), ("stdev", I_DistOrNumber)])], + ~run=inputs => + inputs + ->Prepare.twoNumberInputsRecord3 + ->E.R.bind(Prepare.twoDistOrNumber) + ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToMeanStdev, ~values=_)), + ), + ], + ) +} + +let allFunctions = [NormalFn.toFn, LognormalFn.toFn] From 4b07226b4546ccd8b9ccdf715495ffdca126a82a Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 19 May 2022 17:04:31 -0400 Subject: [PATCH 12/26] Continuing cleanup of FunctionRegistry --- .../src/rescript/FunctionRegistry.res | 151 +++++++++--------- 1 file changed, 73 insertions(+), 78 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index a1138129..31db2269 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -241,38 +241,28 @@ module Registry = { let impossibleError = "Wrong inputs / Logically impossible" module Prepare = { - let twoNumberInputs = (inputs: array) => { + let recordWithTwoArgsToValues = (inputs: array): result, string> => + switch inputs { + | [Record([(_, n1), (_, n2)])] => Ok([n1, n2]) + | _ => Error(impossibleError) + } + + let twoNumberInputs = (inputs: array): result<(float, float), string> => { switch inputs { | [Number(n1), Number(n2)] => Ok(n1, n2) | _ => Error(impossibleError) } } - let twoDistOrNumber = (values: array) => { + let twoDistOrNumber = (values: array): result<(distOrNumber, distOrNumber), string> => { switch values { | [DistOrNumber(a1), DistOrNumber(a2)] => Ok(a1, a2) | _ => Error(impossibleError) } } - let twoNumberInputsRecord = (v1: string, v2: string, inputs: array) => - switch inputs { - | [Record([(name1, n1), (name2, n2)])] if name1 == v1 && name2 == v2 => - twoNumberInputs([n1, n2]) - | _ => Error(impossibleError) - } - - let twoNumberInputsRecord2 = (inputs: array) => - switch inputs { - | [Record([(_, n1), (_, n2)])] => twoNumberInputs([n1, n2]) - | _ => Error(impossibleError) - } - - let twoNumberInputsRecord3 = (inputs: array) => - switch inputs { - | [Record([(_, n1), (_, n2)])] => Ok([n1, n2]) - | _ => Error(impossibleError) - } + let twoDistOrNumberFromRecord = (values: array) => + values->recordWithTwoArgsToValues->E.R.bind(twoDistOrNumber) } module Wrappers = { @@ -281,60 +271,69 @@ module Wrappers = { let symbolicEvDistribution = r => r->Symbolic->evDistribution } -let twoDistsOrNumbers = ( - ~fn: (float, float) => result, - ~values: (distOrNumber, distOrNumber), -) => { - let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) - let sampleSetToExpressionValue = ( - b: Belt.Result.t, - ) => - switch b { - | Ok(r) => Ok(ReducerInterface_ExpressionValue.EvDistribution(SampleSet(r))) - | Error(d) => Error(DistributionTypes.Error.toString(d)) - } +module Process = { + let twoDistsOrNumbersToDist = ( + ~fn: (float, float) => result, + ~values: (distOrNumber, distOrNumber), + ) => { + let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) + let sampleSetToExpressionValue = ( + b: Belt.Result.t, + ) => + switch b { + | Ok(r) => Ok(ReducerInterface_ExpressionValue.EvDistribution(SampleSet(r))) + | Error(d) => Error(DistributionTypes.Error.toString(d)) + } - let mapFnResult = r => - switch r { - | Ok(r) => Ok(GenericDist.sample(r)) - | Error(r) => Error(Operation.Other(r)) - } + let mapFnResult = r => + switch r { + | Ok(r) => Ok(GenericDist.sample(r)) + | Error(r) => Error(Operation.Other(r)) + } - let singleVarSample = (a, fn) => { - let sampleSetResult = - toSampleSet(a) |> E.R2.bind(dist => - SampleSetDist.samplesMap( - ~fn=f => fn(f)->mapFnResult, - dist, - )->E.R2.errMap(r => DistributionTypes.SampleSetError(r)) - ) - sampleSetResult->sampleSetToExpressionValue - } - - switch values { - | (Number(a1), Number(a2)) => fn(a1, a2)->E.R2.fmap(Wrappers.evDistribution) - | (Dist(a1), Number(a2)) => singleVarSample(a1, r => fn(r, a2)) - | (Number(a1), Dist(a2)) => singleVarSample(a2, r => fn(a1, r)) - | (Dist(a1), Dist(a2)) => { - let altFn = (a, b) => fn(a, b)->mapFnResult + let singleVarSample = (a, fn) => { let sampleSetResult = - E.R.merge(toSampleSet(a1), toSampleSet(a2)) - ->E.R2.errMap(DistributionTypes.Error.toString) - ->E.R.bind(((t1, t2)) => { - SampleSetDist.map2(~fn=altFn, ~t1, ~t2)->E.R2.errMap(Operation.Error.toString) - }) - ->E.R2.errMap(r => DistributionTypes.OtherError(r)) + toSampleSet(a) |> E.R2.bind(dist => + SampleSetDist.samplesMap( + ~fn=f => fn(f)->mapFnResult, + dist, + )->E.R2.errMap(r => DistributionTypes.SampleSetError(r)) + ) sampleSetResult->sampleSetToExpressionValue } + + switch values { + | (Number(a1), Number(a2)) => fn(a1, a2)->E.R2.fmap(Wrappers.evDistribution) + | (Dist(a1), Number(a2)) => singleVarSample(a1, r => fn(r, a2)) + | (Number(a1), Dist(a2)) => singleVarSample(a2, r => fn(a1, r)) + | (Dist(a1), Dist(a2)) => { + let altFn = (a, b) => fn(a, b)->mapFnResult + let sampleSetResult = + E.R.merge(toSampleSet(a1), toSampleSet(a2)) + ->E.R2.errMap(DistributionTypes.Error.toString) + ->E.R.bind(((t1, t2)) => { + SampleSetDist.map2(~fn=altFn, ~t1, ~t2)->E.R2.errMap(Operation.Error.toString) + }) + ->E.R2.errMap(r => DistributionTypes.OtherError(r)) + sampleSetResult->sampleSetToExpressionValue + } + } + } + + let twoDistsOrNumbersToDistUsingSymbolicDist = ( + ~fn: (float, float) => result, + ~values, + ) => { + twoDistsOrNumbersToDist(~fn=(a, b) => fn(a, b)->E.R2.fmap(Wrappers.symbolic), ~values) } } module NormalFn = { let fnName = "normal" - let twoFloatsToSymoblic = (a1: float, a2: float) => - SymbolicDist.Normal.make(a1, a2)->E.R2.fmap(Wrappers.symbolic) - let twoFloatsToSymbolic90P = (a1: float, a2: float) => - SymbolicDist.Normal.from90PercentCI(a1, a2)->Wrappers.symbolic->Ok + let twoFloatsToSymoblic = (a1, a2) => + SymbolicDist.Normal.make(a1, a2) + let twoFloatsToSymbolic90P = (a1, a2) => + SymbolicDist.Normal.from90PercentCI(a1, a2)->Ok let toFn = Function.make( ~name="Normal", @@ -345,7 +344,7 @@ module NormalFn = { ~run=inputs => { inputs ->Prepare.twoDistOrNumber - ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToSymoblic, ~values=_)) + ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn=twoFloatsToSymoblic, ~values=_)) }, ), Function.makeDefinition( @@ -353,18 +352,16 @@ module NormalFn = { ~inputs=[I_Record([("mean", I_DistOrNumber), ("stdev", I_DistOrNumber)])], ~run=inputs => inputs - ->Prepare.twoNumberInputsRecord3 - ->E.R.bind(Prepare.twoDistOrNumber) - ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToSymoblic, ~values=_)), + ->Prepare.twoDistOrNumberFromRecord + ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn=twoFloatsToSymoblic, ~values=_)), ), Function.makeDefinition( ~name=fnName, ~inputs=[I_Record([("p5", I_DistOrNumber), ("p95", I_DistOrNumber)])], ~run=inputs => inputs - ->Prepare.twoNumberInputsRecord3 - ->E.R.bind(Prepare.twoDistOrNumber) - ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToSymbolic90P, ~values=_)), + ->Prepare.twoDistOrNumberFromRecord + ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn=twoFloatsToSymbolic90P, ~values=_)), ), ], ) @@ -385,25 +382,23 @@ module LognormalFn = { Function.makeDefinition(~name=fnName, ~inputs=[I_DistOrNumber, I_DistOrNumber], ~run=inputs => inputs ->Prepare.twoDistOrNumber - ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToSymoblic, ~values=_)) + ->E.R.bind(Process.twoDistsOrNumbersToDist(~fn=twoFloatsToSymoblic, ~values=_)) ), Function.makeDefinition( ~name=fnName, ~inputs=[I_Record([("p5", I_DistOrNumber), ("p95", I_DistOrNumber)])], ~run=inputs => inputs - ->Prepare.twoNumberInputsRecord3 - ->E.R.bind(Prepare.twoDistOrNumber) - ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToSymbolic90P, ~values=_)), + ->Prepare.twoDistOrNumberFromRecord + ->E.R.bind(Process.twoDistsOrNumbersToDist(~fn=twoFloatsToSymbolic90P, ~values=_)), ), Function.makeDefinition( ~name=fnName, ~inputs=[I_Record([("mean", I_DistOrNumber), ("stdev", I_DistOrNumber)])], ~run=inputs => inputs - ->Prepare.twoNumberInputsRecord3 - ->E.R.bind(Prepare.twoDistOrNumber) - ->E.R.bind(twoDistsOrNumbers(~fn=twoFloatsToMeanStdev, ~values=_)), + ->Prepare.twoDistOrNumberFromRecord + ->E.R.bind(Process.twoDistsOrNumbersToDist(~fn=twoFloatsToMeanStdev, ~values=_)), ), ], ) From c326d0b229175a561c2e9efafb2280f410c5c95b Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 19 May 2022 18:09:37 -0400 Subject: [PATCH 13/26] More cleaning --- .../src/rescript/FunctionRegistry.res | 73 ++++++++----------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index 31db2269..10f48f43 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -92,11 +92,11 @@ module FnDefinition = { type definitionMatch = MatchSimple.t let getArgValues = (f: fnDefinition, args: array): option> => { - let inputTypes = f.inputs + let mainInputTypes = f.inputs if E.A.length(f.inputs) !== E.A.length(args) { None } else { - E.A.zip(inputTypes, args) + E.A.zip(mainInputTypes, args) ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) ->E.A.O.openIfAllSome } @@ -273,7 +273,7 @@ module Wrappers = { module Process = { let twoDistsOrNumbersToDist = ( - ~fn: (float, float) => result, + ~fn: ((float, float)) => result, ~values: (distOrNumber, distOrNumber), ) => { let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) @@ -303,11 +303,11 @@ module Process = { } switch values { - | (Number(a1), Number(a2)) => fn(a1, a2)->E.R2.fmap(Wrappers.evDistribution) - | (Dist(a1), Number(a2)) => singleVarSample(a1, r => fn(r, a2)) - | (Number(a1), Dist(a2)) => singleVarSample(a2, r => fn(a1, r)) + | (Number(a1), Number(a2)) => fn((a1, a2))->E.R2.fmap(Wrappers.evDistribution) + | (Dist(a1), Number(a2)) => singleVarSample(a1, r => fn((r, a2))) + | (Number(a1), Dist(a2)) => singleVarSample(a2, r => fn((a1, r))) | (Dist(a1), Dist(a2)) => { - let altFn = (a, b) => fn(a, b)->mapFnResult + let altFn = (a, b) => fn((a, b))->mapFnResult let sampleSetResult = E.R.merge(toSampleSet(a1), toSampleSet(a2)) ->E.R2.errMap(DistributionTypes.Error.toString) @@ -321,47 +321,41 @@ module Process = { } let twoDistsOrNumbersToDistUsingSymbolicDist = ( - ~fn: (float, float) => result, + ~fn: ((float, float)) => result, ~values, ) => { - twoDistsOrNumbersToDist(~fn=(a, b) => fn(a, b)->E.R2.fmap(Wrappers.symbolic), ~values) + twoDistsOrNumbersToDist(~fn=r => r->fn->E.R2.fmap(Wrappers.symbolic), ~values) } } +let twoArgs = (fn, (a1, a2)) => fn(a1, a2) + +let process = (~fn, r) => + r->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) + module NormalFn = { let fnName = "normal" - let twoFloatsToSymoblic = (a1, a2) => - SymbolicDist.Normal.make(a1, a2) - let twoFloatsToSymbolic90P = (a1, a2) => - SymbolicDist.Normal.from90PercentCI(a1, a2)->Ok + let mainInputType = I_DistOrNumber let toFn = Function.make( ~name="Normal", ~definitions=[ + Function.makeDefinition(~name=fnName, ~inputs=[mainInputType, mainInputType], ~run=inputs => { + inputs->Prepare.twoDistOrNumber->process(~fn=twoArgs(SymbolicDist.Normal.make)) + }), Function.makeDefinition( ~name=fnName, - ~inputs=[I_DistOrNumber, I_DistOrNumber], - ~run=inputs => { - inputs - ->Prepare.twoDistOrNumber - ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn=twoFloatsToSymoblic, ~values=_)) - }, + ~inputs=[I_Record([("mean", mainInputType), ("stdev", mainInputType)])], + ~run=inputs => + inputs->Prepare.twoDistOrNumberFromRecord->process(~fn=twoArgs(SymbolicDist.Normal.make)), ), Function.makeDefinition( ~name=fnName, - ~inputs=[I_Record([("mean", I_DistOrNumber), ("stdev", I_DistOrNumber)])], + ~inputs=[I_Record([("p5", mainInputType), ("p95", mainInputType)])], ~run=inputs => inputs ->Prepare.twoDistOrNumberFromRecord - ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn=twoFloatsToSymoblic, ~values=_)), - ), - Function.makeDefinition( - ~name=fnName, - ~inputs=[I_Record([("p5", I_DistOrNumber), ("p95", I_DistOrNumber)])], - ~run=inputs => - inputs - ->Prepare.twoDistOrNumberFromRecord - ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn=twoFloatsToSymbolic90P, ~values=_)), + ->process(~fn=r => twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok), ), ], ) @@ -369,36 +363,29 @@ module NormalFn = { module LognormalFn = { let fnName = "lognormal" - let twoFloatsToSymoblic = (a1, a2) => - SymbolicDist.Lognormal.make(a1, a2)->E.R2.fmap(Wrappers.symbolic) - let twoFloatsToSymbolic90P = (a1, a2) => - SymbolicDist.Lognormal.from90PercentCI(a1, a2)->Wrappers.symbolic->Ok - let twoFloatsToMeanStdev = (a1, a2) => - SymbolicDist.Lognormal.fromMeanAndStdev(a1, a2)->E.R2.fmap(Wrappers.symbolic) + let mainInputType = I_DistOrNumber let toFn = Function.make( ~name="Lognormal", ~definitions=[ - Function.makeDefinition(~name=fnName, ~inputs=[I_DistOrNumber, I_DistOrNumber], ~run=inputs => - inputs - ->Prepare.twoDistOrNumber - ->E.R.bind(Process.twoDistsOrNumbersToDist(~fn=twoFloatsToSymoblic, ~values=_)) + Function.makeDefinition(~name=fnName, ~inputs=[mainInputType, mainInputType], ~run=inputs => + inputs->Prepare.twoDistOrNumber->process(~fn=twoArgs(SymbolicDist.Lognormal.make)) ), Function.makeDefinition( ~name=fnName, - ~inputs=[I_Record([("p5", I_DistOrNumber), ("p95", I_DistOrNumber)])], + ~inputs=[I_Record([("p5", mainInputType), ("p95", mainInputType)])], ~run=inputs => inputs ->Prepare.twoDistOrNumberFromRecord - ->E.R.bind(Process.twoDistsOrNumbersToDist(~fn=twoFloatsToSymbolic90P, ~values=_)), + ->process(~fn=r => twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok), ), Function.makeDefinition( ~name=fnName, - ~inputs=[I_Record([("mean", I_DistOrNumber), ("stdev", I_DistOrNumber)])], + ~inputs=[I_Record([("mean", mainInputType), ("stdev", mainInputType)])], ~run=inputs => inputs ->Prepare.twoDistOrNumberFromRecord - ->E.R.bind(Process.twoDistsOrNumbersToDist(~fn=twoFloatsToMeanStdev, ~values=_)), + ->process(~fn=twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev)), ), ], ) From 0b85b125510720fdf624d2bf77d921bf23433b10 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 19 May 2022 18:17:31 -0400 Subject: [PATCH 14/26] Moved matching functionality to dedicated module --- .../src/rescript/FunctionRegistry.res | 281 ++++++++++-------- 1 file changed, 150 insertions(+), 131 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry.res index 10f48f43..8f69b3d4 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry.res @@ -56,41 +56,162 @@ let rec matchInput = (input: itype, r: expressionValue): option => | _ => None } -module MatchSimple = { - type t = DifferentName | SameNameDifferentArguments | FullMatch +module Matcher = { + module MatchSimple = { + type t = DifferentName | SameNameDifferentArguments | FullMatch - let isFullMatch = (match: t) => - switch match { - | FullMatch => true - | _ => false + let isFullMatch = (match: t) => + switch match { + | FullMatch => true + | _ => false + } + + let isNameMatchOnly = (match: t) => + switch match { + | SameNameDifferentArguments => true + | _ => false + } + } + + module Match = { + type t<'a, 'b> = DifferentName | SameNameDifferentArguments('a) | FullMatch('b) + + let isFullMatch = (match: t<'a, 'b>): bool => + switch match { + | FullMatch(_) => true + | _ => false + } + + let isNameMatchOnly = (match: t<'a, 'b>) => + switch match { + | SameNameDifferentArguments(_) => true + | _ => false + } + } + + module FnDefinition = { + type definitionMatch = MatchSimple.t + + let getArgValues = (f: fnDefinition, args: array): option> => { + let mainInputTypes = f.inputs + if E.A.length(f.inputs) !== E.A.length(args) { + None + } else { + E.A.zip(mainInputTypes, args) + ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) + ->E.A.O.openIfAllSome + } } - let isNameMatchOnly = (match: t) => - switch match { - | SameNameDifferentArguments => true - | _ => false - } -} - -module Match = { - type t<'a, 'b> = DifferentName | SameNameDifferentArguments('a) | FullMatch('b) - - let isFullMatch = (match: t<'a, 'b>): bool => - switch match { - | FullMatch(_) => true - | _ => false + let matchAssumingSameName = (f: fnDefinition, args: array) => { + switch getArgValues(f, args) { + | Some(_) => MatchSimple.FullMatch + | None => MatchSimple.SameNameDifferentArguments + } } - let isNameMatchOnly = (match: t<'a, 'b>) => - switch match { - | SameNameDifferentArguments(_) => true - | _ => false + let match = (f: fnDefinition, fnName: string, args: array) => { + if f.name !== fnName { + MatchSimple.DifferentName + } else { + matchAssumingSameName(f, args) + } } + } + + module Function = { + type definitionId = int + type match = Match.t, definitionId> + + let match = (f: function, fnName: string, args: array): match => { + let matchedDefinition = () => + E.A.getIndexBy(f.definitions, r => + MatchSimple.isFullMatch(FnDefinition.match(r, fnName, args)) + ) |> E.O.fmap(r => Match.FullMatch(r)) + let getMatchedNameOnlyDefinition = () => { + let nameMatchIndexes = + f.definitions + ->E.A2.fmapi((index, r) => + MatchSimple.isNameMatchOnly(FnDefinition.match(r, fnName, args)) ? Some(index) : None + ) + ->E.A.O.concatSomes + switch nameMatchIndexes { + | [] => None + | elements => Some(Match.SameNameDifferentArguments(elements)) + } + } + + E.A.O.firstSomeFnWithDefault( + [matchedDefinition, getMatchedNameOnlyDefinition], + Match.DifferentName, + ) + } + } + + module RegistryMatch = { + type match = { + fnName: string, + inputIndex: int, + } + type t = Match.t, match> + let makeMatch = (fnName: string, inputIndex: int) => {fnName: fnName, inputIndex: inputIndex} + } + + module Registry = { + let findExactMatches = (r: registry, fnName: string, args: array) => { + let functionMatchPairs = r->E.A2.fmap(l => (l, Function.match(l, fnName, args))) + let getFullMatch = E.A.getBy(functionMatchPairs, ((_, match: Function.match)) => + Match.isFullMatch(match) + ) + let fullMatch: option = getFullMatch->E.O.bind(((fn, match)) => + switch match { + | FullMatch(index) => Some(RegistryMatch.makeMatch(fn.name, index)) + | _ => None + } + ) + fullMatch + } + + let findNameMatches = (r: registry, fnName: string, args: array) => { + let functionMatchPairs = r->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) + ->E.A.O.concatSomes + let matches = + getNameMatches + ->E.A2.fmap(((fn, match)) => + switch match { + | SameNameDifferentArguments(indexes) => + indexes->E.A2.fmap(index => RegistryMatch.makeMatch(fn.name, index)) + | _ => [] + } + ) + ->Belt.Array.concatMany + E.A.toNoneIfEmpty(matches) + } + + let findMatches = (r: registry, fnName: string, args: array) => { + switch findExactMatches(r, fnName, args) { + | Some(r) => Match.FullMatch(r) + | None => + switch findNameMatches(r, fnName, args) { + | Some(r) => Match.SameNameDifferentArguments(r) + | None => Match.DifferentName + } + } + } + + let fullMatchToDef = (registry: registry, {fnName, inputIndex}: RegistryMatch.match): option< + fnDefinition, + > => + registry + ->E.A.getBy(fn => fn.name === fnName) + ->E.O.bind(fn => E.A.get(fn.definitions, inputIndex)) + } } module FnDefinition = { - type definitionMatch = MatchSimple.t - let getArgValues = (f: fnDefinition, args: array): option> => { let mainInputTypes = f.inputs if E.A.length(f.inputs) !== E.A.length(args) { @@ -101,22 +222,6 @@ module FnDefinition = { ->E.A.O.openIfAllSome } } - - let matchAssumingSameName = (f: fnDefinition, args: array) => { - switch getArgValues(f, args) { - | Some(_) => MatchSimple.FullMatch - | None => MatchSimple.SameNameDifferentArguments - } - } - - let match = (f: fnDefinition, fnName: string, args: array) => { - if f.name !== fnName { - MatchSimple.DifferentName - } else { - matchAssumingSameName(f, args) - } - } - let run = (f: fnDefinition, args: array) => { let argValues = getArgValues(f, args) switch argValues { @@ -128,8 +233,6 @@ module FnDefinition = { module Function = { type definitionId = int - type match = Match.t, definitionId> - let make = (~name, ~definitions): function => { name: name, definitions: definitions, @@ -140,97 +243,13 @@ module Function = { inputs: inputs, run: run, } - - let match = (f: function, fnName: string, args: array): match => { - let matchedDefinition = () => - E.A.getIndexBy(f.definitions, r => - MatchSimple.isFullMatch(FnDefinition.match(r, fnName, args)) - ) |> E.O.fmap(r => Match.FullMatch(r)) - let getMatchedNameOnlyDefinition = () => { - let nameMatchIndexes = - f.definitions - ->E.A2.fmapi((index, r) => - MatchSimple.isNameMatchOnly(FnDefinition.match(r, fnName, args)) ? Some(index) : None - ) - ->E.A.O.concatSomes - switch nameMatchIndexes { - | [] => None - | elements => Some(Match.SameNameDifferentArguments(elements)) - } - } - - E.A.O.firstSomeFnWithDefault( - [matchedDefinition, getMatchedNameOnlyDefinition], - Match.DifferentName, - ) - } -} - -module RegistryMatch = { - type match = { - fnName: string, - inputIndex: int, - } - type t = Match.t, match> - let makeMatch = (fnName: string, inputIndex: int) => {fnName: fnName, inputIndex: inputIndex} } module Registry = { - let findExactMatches = (r: registry, fnName: string, args: array) => { - let functionMatchPairs = r->E.A2.fmap(l => (l, Function.match(l, fnName, args))) - let getFullMatch = E.A.getBy(functionMatchPairs, ((_, match: Function.match)) => - Match.isFullMatch(match) - ) - let fullMatch: option = getFullMatch->E.O.bind(((fn, match)) => - switch match { - | FullMatch(index) => Some(RegistryMatch.makeMatch(fn.name, index)) - | _ => None - } - ) - fullMatch - } - - let findNameMatches = (r: registry, fnName: string, args: array) => { - let functionMatchPairs = r->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) - ->E.A.O.concatSomes - let matches = - getNameMatches - ->E.A2.fmap(((fn, match)) => - switch match { - | SameNameDifferentArguments(indexes) => - indexes->E.A2.fmap(index => RegistryMatch.makeMatch(fn.name, index)) - | _ => [] - } - ) - ->Belt.Array.concatMany - E.A.toNoneIfEmpty(matches) - } - - let findMatches = (r: registry, fnName: string, args: array) => { - switch findExactMatches(r, fnName, args) { - | Some(r) => Match.FullMatch(r) - | None => - switch findNameMatches(r, fnName, args) { - | Some(r) => Match.SameNameDifferentArguments(r) - | None => Match.DifferentName - } - } - } - - let fullMatchToDef = (registry: registry, {fnName, inputIndex}: RegistryMatch.match): option< - fnDefinition, - > => - registry - ->E.A.getBy(fn => fn.name === fnName) - ->E.O.bind(fn => E.A.get(fn.definitions, inputIndex)) - let matchAndRun = (r: registry, fnName: string, args: array) => { - switch findMatches(r, fnName, args) { - | Match.FullMatch(m) => - fullMatchToDef(r, m)->E.O2.fmap(r => { + switch Matcher.Registry.findMatches(r, fnName, args) { + | Matcher.Match.FullMatch(m) => + Matcher.Registry.fullMatchToDef(r, m)->E.O2.fmap(r => { FnDefinition.run(r, args) }) | _ => None From 2c0dc75403543ad73000d569118f36cc40dca709 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Thu, 19 May 2022 18:24:56 -0400 Subject: [PATCH 15/26] Split FunctionRegistry into multiple files --- .../FunctionRegistry_Core.res} | 155 ------------------ .../FunctionRegistry_Helpers.res | 91 ++++++++++ .../FunctionRegistry_Library.res | 67 ++++++++ .../ReducerInterface_GenericDistribution.res | 11 +- 4 files changed, 163 insertions(+), 161 deletions(-) rename packages/squiggle-lang/src/rescript/{FunctionRegistry.res => FunctionRegistry/FunctionRegistry_Core.res} (60%) create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res similarity index 60% rename from packages/squiggle-lang/src/rescript/FunctionRegistry.res rename to packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 8f69b3d4..1afd9a66 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -256,158 +256,3 @@ module Registry = { } } } - -let impossibleError = "Wrong inputs / Logically impossible" - -module Prepare = { - let recordWithTwoArgsToValues = (inputs: array): result, string> => - switch inputs { - | [Record([(_, n1), (_, n2)])] => Ok([n1, n2]) - | _ => Error(impossibleError) - } - - let twoNumberInputs = (inputs: array): result<(float, float), string> => { - switch inputs { - | [Number(n1), Number(n2)] => Ok(n1, n2) - | _ => Error(impossibleError) - } - } - - let twoDistOrNumber = (values: array): result<(distOrNumber, distOrNumber), string> => { - switch values { - | [DistOrNumber(a1), DistOrNumber(a2)] => Ok(a1, a2) - | _ => Error(impossibleError) - } - } - - let twoDistOrNumberFromRecord = (values: array) => - values->recordWithTwoArgsToValues->E.R.bind(twoDistOrNumber) -} - -module Wrappers = { - let symbolic = r => DistributionTypes.Symbolic(r) - let evDistribution = r => ReducerInterface_ExpressionValue.EvDistribution(r) - let symbolicEvDistribution = r => r->Symbolic->evDistribution -} - -module Process = { - let twoDistsOrNumbersToDist = ( - ~fn: ((float, float)) => result, - ~values: (distOrNumber, distOrNumber), - ) => { - let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) - let sampleSetToExpressionValue = ( - b: Belt.Result.t, - ) => - switch b { - | Ok(r) => Ok(ReducerInterface_ExpressionValue.EvDistribution(SampleSet(r))) - | Error(d) => Error(DistributionTypes.Error.toString(d)) - } - - let mapFnResult = r => - switch r { - | Ok(r) => Ok(GenericDist.sample(r)) - | Error(r) => Error(Operation.Other(r)) - } - - let singleVarSample = (a, fn) => { - let sampleSetResult = - toSampleSet(a) |> E.R2.bind(dist => - SampleSetDist.samplesMap( - ~fn=f => fn(f)->mapFnResult, - dist, - )->E.R2.errMap(r => DistributionTypes.SampleSetError(r)) - ) - sampleSetResult->sampleSetToExpressionValue - } - - switch values { - | (Number(a1), Number(a2)) => fn((a1, a2))->E.R2.fmap(Wrappers.evDistribution) - | (Dist(a1), Number(a2)) => singleVarSample(a1, r => fn((r, a2))) - | (Number(a1), Dist(a2)) => singleVarSample(a2, r => fn((a1, r))) - | (Dist(a1), Dist(a2)) => { - let altFn = (a, b) => fn((a, b))->mapFnResult - let sampleSetResult = - E.R.merge(toSampleSet(a1), toSampleSet(a2)) - ->E.R2.errMap(DistributionTypes.Error.toString) - ->E.R.bind(((t1, t2)) => { - SampleSetDist.map2(~fn=altFn, ~t1, ~t2)->E.R2.errMap(Operation.Error.toString) - }) - ->E.R2.errMap(r => DistributionTypes.OtherError(r)) - sampleSetResult->sampleSetToExpressionValue - } - } - } - - let twoDistsOrNumbersToDistUsingSymbolicDist = ( - ~fn: ((float, float)) => result, - ~values, - ) => { - twoDistsOrNumbersToDist(~fn=r => r->fn->E.R2.fmap(Wrappers.symbolic), ~values) - } -} - -let twoArgs = (fn, (a1, a2)) => fn(a1, a2) - -let process = (~fn, r) => - r->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) - -module NormalFn = { - let fnName = "normal" - let mainInputType = I_DistOrNumber - - let toFn = Function.make( - ~name="Normal", - ~definitions=[ - Function.makeDefinition(~name=fnName, ~inputs=[mainInputType, mainInputType], ~run=inputs => { - inputs->Prepare.twoDistOrNumber->process(~fn=twoArgs(SymbolicDist.Normal.make)) - }), - Function.makeDefinition( - ~name=fnName, - ~inputs=[I_Record([("mean", mainInputType), ("stdev", mainInputType)])], - ~run=inputs => - inputs->Prepare.twoDistOrNumberFromRecord->process(~fn=twoArgs(SymbolicDist.Normal.make)), - ), - Function.makeDefinition( - ~name=fnName, - ~inputs=[I_Record([("p5", mainInputType), ("p95", mainInputType)])], - ~run=inputs => - inputs - ->Prepare.twoDistOrNumberFromRecord - ->process(~fn=r => twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok), - ), - ], - ) -} - -module LognormalFn = { - let fnName = "lognormal" - let mainInputType = I_DistOrNumber - - let toFn = Function.make( - ~name="Lognormal", - ~definitions=[ - Function.makeDefinition(~name=fnName, ~inputs=[mainInputType, mainInputType], ~run=inputs => - inputs->Prepare.twoDistOrNumber->process(~fn=twoArgs(SymbolicDist.Lognormal.make)) - ), - Function.makeDefinition( - ~name=fnName, - ~inputs=[I_Record([("p5", mainInputType), ("p95", mainInputType)])], - ~run=inputs => - inputs - ->Prepare.twoDistOrNumberFromRecord - ->process(~fn=r => twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok), - ), - Function.makeDefinition( - ~name=fnName, - ~inputs=[I_Record([("mean", mainInputType), ("stdev", mainInputType)])], - ~run=inputs => - inputs - ->Prepare.twoDistOrNumberFromRecord - ->process(~fn=twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev)), - ), - ], - ) -} - -let allFunctions = [NormalFn.toFn, LognormalFn.toFn] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res new file mode 100644 index 00000000..487fa811 --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -0,0 +1,91 @@ +open FunctionRegistry_Core + +let impossibleError = "Wrong inputs / Logically impossible" + +module Wrappers = { + let symbolic = r => DistributionTypes.Symbolic(r) + let evDistribution = r => ReducerInterface_ExpressionValue.EvDistribution(r) + let symbolicEvDistribution = r => r->Symbolic->evDistribution +} + +module Prepare = { + let recordWithTwoArgsToValues = (inputs: array): result, string> => + switch inputs { + | [Record([(_, n1), (_, n2)])] => Ok([n1, n2]) + | _ => Error(impossibleError) + } + + let twoNumberInputs = (inputs: array): result<(float, float), string> => { + switch inputs { + | [Number(n1), Number(n2)] => Ok(n1, n2) + | _ => Error(impossibleError) + } + } + + let twoDistOrNumber = (values: array): result<(distOrNumber, distOrNumber), string> => { + switch values { + | [DistOrNumber(a1), DistOrNumber(a2)] => Ok(a1, a2) + | _ => Error(impossibleError) + } + } + + let twoDistOrNumberFromRecord = (values: array) => + values->recordWithTwoArgsToValues->E.R.bind(twoDistOrNumber) +} + +module Process = { + let twoDistsOrNumbersToDist = ( + ~fn: ((float, float)) => result, + ~values: (distOrNumber, distOrNumber), + ) => { + let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) + let sampleSetToExpressionValue = ( + b: Belt.Result.t, + ) => + switch b { + | Ok(r) => Ok(ReducerInterface_ExpressionValue.EvDistribution(SampleSet(r))) + | Error(d) => Error(DistributionTypes.Error.toString(d)) + } + + let mapFnResult = r => + switch r { + | Ok(r) => Ok(GenericDist.sample(r)) + | Error(r) => Error(Operation.Other(r)) + } + + let singleVarSample = (a, fn) => { + let sampleSetResult = + toSampleSet(a) |> E.R2.bind(dist => + SampleSetDist.samplesMap( + ~fn=f => fn(f)->mapFnResult, + dist, + )->E.R2.errMap(r => DistributionTypes.SampleSetError(r)) + ) + sampleSetResult->sampleSetToExpressionValue + } + + switch values { + | (Number(a1), Number(a2)) => fn((a1, a2))->E.R2.fmap(Wrappers.evDistribution) + | (Dist(a1), Number(a2)) => singleVarSample(a1, r => fn((r, a2))) + | (Number(a1), Dist(a2)) => singleVarSample(a2, r => fn((a1, r))) + | (Dist(a1), Dist(a2)) => { + let altFn = (a, b) => fn((a, b))->mapFnResult + let sampleSetResult = + E.R.merge(toSampleSet(a1), toSampleSet(a2)) + ->E.R2.errMap(DistributionTypes.Error.toString) + ->E.R.bind(((t1, t2)) => { + SampleSetDist.map2(~fn=altFn, ~t1, ~t2)->E.R2.errMap(Operation.Error.toString) + }) + ->E.R2.errMap(r => DistributionTypes.OtherError(r)) + sampleSetResult->sampleSetToExpressionValue + } + } + } + + let twoDistsOrNumbersToDistUsingSymbolicDist = ( + ~fn: ((float, float)) => result, + ~values, + ) => { + twoDistsOrNumbersToDist(~fn=r => r->fn->E.R2.fmap(Wrappers.symbolic), ~values) + } +} \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res new file mode 100644 index 00000000..f0ac6b9a --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -0,0 +1,67 @@ +open FunctionRegistry_Core +open FunctionRegistry_Helpers + +let twoArgs = (fn, (a1, a2)) => fn(a1, a2) + +let process = (~fn, r) => + r->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) + +module NormalFn = { + let fnName = "normal" + let mainInputType = I_DistOrNumber + + let toFn = Function.make( + ~name="Normal", + ~definitions=[ + Function.makeDefinition(~name=fnName, ~inputs=[mainInputType, mainInputType], ~run=inputs => { + inputs->Prepare.twoDistOrNumber->process(~fn=twoArgs(SymbolicDist.Normal.make)) + }), + Function.makeDefinition( + ~name=fnName, + ~inputs=[I_Record([("mean", mainInputType), ("stdev", mainInputType)])], + ~run=inputs => + inputs->Prepare.twoDistOrNumberFromRecord->process(~fn=twoArgs(SymbolicDist.Normal.make)), + ), + Function.makeDefinition( + ~name=fnName, + ~inputs=[I_Record([("p5", mainInputType), ("p95", mainInputType)])], + ~run=inputs => + inputs + ->Prepare.twoDistOrNumberFromRecord + ->process(~fn=r => twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok), + ), + ], + ) +} + +module LognormalFn = { + let fnName = "lognormal" + let mainInputType = I_DistOrNumber + + let toFn = Function.make( + ~name="Lognormal", + ~definitions=[ + Function.makeDefinition(~name=fnName, ~inputs=[mainInputType, mainInputType], ~run=inputs => + inputs->Prepare.twoDistOrNumber->process(~fn=twoArgs(SymbolicDist.Lognormal.make)) + ), + Function.makeDefinition( + ~name=fnName, + ~inputs=[I_Record([("p5", mainInputType), ("p95", mainInputType)])], + ~run=inputs => + inputs + ->Prepare.twoDistOrNumberFromRecord + ->process(~fn=r => twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok), + ), + Function.makeDefinition( + ~name=fnName, + ~inputs=[I_Record([("mean", mainInputType), ("stdev", mainInputType)])], + ~run=inputs => + inputs + ->Prepare.twoDistOrNumberFromRecord + ->process(~fn=twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev)), + ), + ], + ) +} + +let allFunctions = [NormalFn.toFn, LognormalFn.toFn] diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 2167d9f2..0beb236e 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -387,13 +387,12 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result< | GenDistError(err) => Error(REDistributionError(err)) } -let registered = FunctionRegistry.allFunctions +let registered = FunctionRegistry_Library.allFunctions -let tryRegistry = (call: ExpressionValue.functionCall) => { - let (fnName, args) = call - let response = FunctionRegistry.Registry.matchAndRun(registered, fnName, args) - let foo = response->E.O2.fmap(r => r->E.R2.errMap(s => Reducer_ErrorValue.RETodo(s))) - foo +let tryRegistry = ((fnName, args): ExpressionValue.functionCall) => { + FunctionRegistry_Core.Registry.matchAndRun(registered, fnName, args)->E.O2.fmap( + E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), + ) } let dispatch = (call: ExpressionValue.functionCall, environment) => { From d9cbe37a5a4990b1d939259e7df26c7a672ffe9a Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 20 May 2022 17:36:40 -0400 Subject: [PATCH 16/26] Added main distributions --- .../FunctionRegistry_Helpers.res | 29 +++++++- .../FunctionRegistry_Library.res | 74 +++++++++---------- .../ReducerInterface_GenericDistribution.res | 26 ------- 3 files changed, 61 insertions(+), 68 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res index 487fa811..aa2fa4b1 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -88,4 +88,31 @@ module Process = { ) => { twoDistsOrNumbersToDist(~fn=r => r->fn->E.R2.fmap(Wrappers.symbolic), ~values) } -} \ No newline at end of file +} + +module TwoArgDist = { + let process = (~fn, r) => + r->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) + + let mkRegular = (name, fn) => { + Function.makeDefinition(~name, ~inputs=[I_DistOrNumber, I_DistOrNumber], ~run=inputs => + inputs->Prepare.twoDistOrNumber->process(~fn) + ) + } + + let mkDef90th = (name, fn) => { + Function.makeDefinition( + ~name, + ~inputs=[I_Record([("p5", I_DistOrNumber), ("p95", I_DistOrNumber)])], + ~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn), + ) + } + + let mkDefMeanStdev = (name, fn) => { + Function.makeDefinition( + ~name, + ~inputs=[I_Record([("mean", I_DistOrNumber), ("stdev", I_DistOrNumber)])], + ~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn), + ) + } +} diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index f0ac6b9a..fe579f2c 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -3,65 +3,57 @@ open FunctionRegistry_Helpers let twoArgs = (fn, (a1, a2)) => fn(a1, a2) -let process = (~fn, r) => - r->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) - module NormalFn = { let fnName = "normal" - let mainInputType = I_DistOrNumber let toFn = Function.make( ~name="Normal", ~definitions=[ - Function.makeDefinition(~name=fnName, ~inputs=[mainInputType, mainInputType], ~run=inputs => { - inputs->Prepare.twoDistOrNumber->process(~fn=twoArgs(SymbolicDist.Normal.make)) - }), - Function.makeDefinition( - ~name=fnName, - ~inputs=[I_Record([("mean", mainInputType), ("stdev", mainInputType)])], - ~run=inputs => - inputs->Prepare.twoDistOrNumberFromRecord->process(~fn=twoArgs(SymbolicDist.Normal.make)), - ), - Function.makeDefinition( - ~name=fnName, - ~inputs=[I_Record([("p5", mainInputType), ("p95", mainInputType)])], - ~run=inputs => - inputs - ->Prepare.twoDistOrNumberFromRecord - ->process(~fn=r => twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok), - ), + TwoArgDist.mkRegular(fnName, twoArgs(SymbolicDist.Normal.make)), + TwoArgDist.mkDef90th(fnName, r => twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok), + TwoArgDist.mkDefMeanStdev(fnName, twoArgs(SymbolicDist.Normal.make)), ], ) } module LognormalFn = { let fnName = "lognormal" - let mainInputType = I_DistOrNumber let toFn = Function.make( ~name="Lognormal", ~definitions=[ - Function.makeDefinition(~name=fnName, ~inputs=[mainInputType, mainInputType], ~run=inputs => - inputs->Prepare.twoDistOrNumber->process(~fn=twoArgs(SymbolicDist.Lognormal.make)) - ), - Function.makeDefinition( - ~name=fnName, - ~inputs=[I_Record([("p5", mainInputType), ("p95", mainInputType)])], - ~run=inputs => - inputs - ->Prepare.twoDistOrNumberFromRecord - ->process(~fn=r => twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok), - ), - Function.makeDefinition( - ~name=fnName, - ~inputs=[I_Record([("mean", mainInputType), ("stdev", mainInputType)])], - ~run=inputs => - inputs - ->Prepare.twoDistOrNumberFromRecord - ->process(~fn=twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev)), - ), + TwoArgDist.mkRegular(fnName, twoArgs(SymbolicDist.Lognormal.make)), + TwoArgDist.mkDef90th(fnName, r => twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok), + TwoArgDist.mkDefMeanStdev(fnName, twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev)), ], ) } +let more = [ + Function.make( + ~name="Uniform", + ~definitions=[TwoArgDist.mkRegular("uniform", twoArgs(SymbolicDist.Uniform.make))], + ), + Function.make( + ~name="Beta", + ~definitions=[TwoArgDist.mkRegular("beta", twoArgs(SymbolicDist.Beta.make))], + ), + Function.make( + ~name="Cauchy", + ~definitions=[TwoArgDist.mkRegular("cauchy", twoArgs(SymbolicDist.Cauchy.make))], + ), + Function.make( + ~name="Gamma", + ~definitions=[TwoArgDist.mkRegular("gamma", twoArgs(SymbolicDist.Gamma.make))], + ), + Function.make( + ~name="Logistic", + ~definitions=[TwoArgDist.mkRegular("logistic", twoArgs(SymbolicDist.Logistic.make))], + ), + Function.make( + ~name="To", + ~definitions=[TwoArgDist.mkRegular("cauchy", twoArgs(SymbolicDist.From90thPercentile.make))], + ) +] + let allFunctions = [NormalFn.toFn, LognormalFn.toFn] diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 0beb236e..714ad47b 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -186,19 +186,6 @@ module SymbolicConstructors = { | _ => Error("Unreachable state") } - let twoFloat = name => - switch name { - | "normal" => Ok(SymbolicDist.Normal.make) - | "uniform" => Ok(SymbolicDist.Uniform.make) - | "beta" => Ok(SymbolicDist.Beta.make) - | "lognormal" => Ok(SymbolicDist.Lognormal.make) - | "logistic" => Ok(SymbolicDist.Logistic.make) - | "cauchy" => Ok(SymbolicDist.Cauchy.make) - | "gamma" => Ok(SymbolicDist.Gamma.make) - | "to" => Ok(SymbolicDist.From90thPercentile.make) - | _ => Error("Unreachable state") - } - let threeFloat = name => switch name { | "triangular" => Ok(SymbolicDist.Triangular.make) @@ -226,19 +213,6 @@ let dispatchToGenericOutput = ( ->SymbolicConstructors.symbolicResultToOutput | ("delta", [EvNumber(f)]) => SymbolicDist.Float.makeSafe(f)->SymbolicConstructors.symbolicResultToOutput - | ( - ("uniform" - | "beta" - | "lognormal" - | "cauchy" - | "gamma" - | "to" - | "logistic") as fnName, - [EvNumber(f1), EvNumber(f2)], - ) => - SymbolicConstructors.twoFloat(fnName) - ->E.R.bind(r => r(f1, f2)) - ->SymbolicConstructors.symbolicResultToOutput | ("triangular" as fnName, [EvNumber(f1), EvNumber(f2), EvNumber(f3)]) => SymbolicConstructors.threeFloat(fnName) ->E.R.bind(r => r(f1, f2, f3)) From c9d6302cbfd23dbde28b332eb2670c05c0d46253 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 20 May 2022 18:05:45 -0400 Subject: [PATCH 17/26] Add better error message when wrong arguments passed --- .../FunctionRegistry_Core.res | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 1afd9a66..23e1e780 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -10,6 +10,21 @@ type rec itype = and iRecord = array and iRecordParam = (string, itype) +module Itype = { + let rec toString = (t: itype) => + switch t { + | I_Number => "number" + | I_Numeric => "numeric" + | I_DistOrNumber => "distOrNumber" + | I_Record(r) => { + let input = ((name, itype): iRecordParam) => `${name}: ${toString(itype)}` + `record({${r->E.A2.fmap(input)->E.A2.joinWith(", ")}})` + } + | I_Array(r) => `record(${r->E.A2.fmap(toString)->E.A2.joinWith(", ")})` + | I_Option(v) => `option(${toString(v)})` + } +} + type rec value = | Number(float) | Dist(DistributionTypes.genericDist) @@ -202,7 +217,7 @@ module Matcher = { } } - let fullMatchToDef = (registry: registry, {fnName, inputIndex}: RegistryMatch.match): option< + let matchToDef = (registry: registry, {fnName, inputIndex}: RegistryMatch.match): option< fnDefinition, > => registry @@ -212,9 +227,10 @@ module Matcher = { } module FnDefinition = { - let getArgValues = (f: fnDefinition, args: array): option> => { - let mainInputTypes = f.inputs - if E.A.length(f.inputs) !== E.A.length(args) { + type t = fnDefinition + let getArgValues = (t: t, args: array): option> => { + let mainInputTypes = t.inputs + if E.A.length(t.inputs) !== E.A.length(args) { None } else { E.A.zip(mainInputTypes, args) @@ -222,10 +238,13 @@ module FnDefinition = { ->E.A.O.openIfAllSome } } - let run = (f: fnDefinition, args: array) => { - let argValues = getArgValues(f, args) + + let defToString = (t: t) => t.inputs->E.A2.fmap(Itype.toString)->E.A2.joinWith(", ") + + let run = (t: t, args: array) => { + let argValues = getArgValues(t, args) switch argValues { - | Some(values) => f.run(values) + | Some(values) => t.run(values) | None => Error("Impossible") } } @@ -247,11 +266,19 @@ module Function = { module Registry = { let matchAndRun = (r: registry, fnName: string, args: array) => { + let matchToDef = m => Matcher.Registry.matchToDef(r, m) + let showNameMatchDefinitions = matches => { + let defs = + matches + ->E.A2.fmap(matchToDef) + ->E.A.O.concatSomes + ->E.A2.fmap(r => `[${fnName}(${FnDefinition.defToString(r)})]`) + ->E.A2.joinWith("; ") + `There are function matches for ${fnName}(), but with different arguments: ${defs}` + } switch Matcher.Registry.findMatches(r, fnName, args) { - | Matcher.Match.FullMatch(m) => - Matcher.Registry.fullMatchToDef(r, m)->E.O2.fmap(r => { - FnDefinition.run(r, args) - }) + | Matcher.Match.FullMatch(match) => match->matchToDef->E.O2.fmap(FnDefinition.run(_, args)) + | SameNameDifferentArguments(m) => Some(Error(showNameMatchDefinitions(m))) | _ => None } } From 390ac2e2bb54ade3dcdb832f9bf9c750cd75639b Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 20 May 2022 22:53:53 -0400 Subject: [PATCH 18/26] Renamed itype->frType, value-> frValue --- .../FunctionRegistry_Core.res | 188 +++++++++--------- .../FunctionRegistry_Helpers.res | 37 ++-- .../FunctionRegistry_Library.res | 2 +- .../squiggle-lang/src/rescript/Utility/E.res | 3 + 4 files changed, 121 insertions(+), 109 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 23e1e780..5e9e877e 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -1,43 +1,39 @@ type expressionValue = ReducerInterface_ExpressionValue.expressionValue -type rec itype = - | I_Number - | I_Numeric - | I_DistOrNumber - | I_Record(iRecord) - | I_Array(array) - | I_Option(itype) -and iRecord = array -and iRecordParam = (string, itype) +/* + Function Registry "Type". A type, without any other information. + Like, #Float +*/ +type rec frType = + | FRTypeNumber + | FRTypeNumeric + | FRTypeDistOrNumber + | FRTypeRecord(frTypeRecord) + | FRTypeArray(array) + | FRTypeOption(frType) +and frTypeRecord = array +and frTypeRecordParam = (string, frType) -module Itype = { - let rec toString = (t: itype) => - switch t { - | I_Number => "number" - | I_Numeric => "numeric" - | I_DistOrNumber => "distOrNumber" - | I_Record(r) => { - let input = ((name, itype): iRecordParam) => `${name}: ${toString(itype)}` - `record({${r->E.A2.fmap(input)->E.A2.joinWith(", ")}})` - } - | I_Array(r) => `record(${r->E.A2.fmap(toString)->E.A2.joinWith(", ")})` - | I_Option(v) => `option(${toString(v)})` - } +/* + Function Registry "Value". A type, with the information of that type. + Like, #Float(40.0) +*/ +type rec frValue = + | FRValueNumber(float) + | FRValueDist(DistributionTypes.genericDist) + | FRValueOption(option) + | FRValueDistOrNumber(frValueDistOrNumber) + | FRValueRecord(frValueRecord) +and frValueRecord = array +and frValueRecordParam = (string, frValue) +and frValueDistOrNumber = FRValueNumber(float) | FRValueDist(DistributionTypes.genericDist) + +type fnDefinition = { + name: string, + inputs: array, + run: array => result, } -type rec value = - | Number(float) - | Dist(DistributionTypes.genericDist) - | Option(option) - | DistOrNumber(distOrNumber) - | Record(record) -and record = array<(string, value)> -and distOrNumber = Number(float) | Dist(DistributionTypes.genericDist) - -type runFn = array => result - -type fnDefinition = {name: string, inputs: array, run: runFn} - type function = { name: string, definitions: array, @@ -45,31 +41,58 @@ type function = { type registry = array -let rec matchInput = (input: itype, r: expressionValue): option => - switch (input, r) { - | (I_Number, EvNumber(f)) => Some(Number(f)) - | (I_DistOrNumber, EvNumber(f)) => Some(DistOrNumber(Number(f))) - | (I_DistOrNumber, EvDistribution(Symbolic(#Float(f)))) => Some(DistOrNumber(Number(f))) - | (I_DistOrNumber, EvDistribution(f)) => Some(DistOrNumber(Dist(f))) - | (I_Numeric, EvNumber(f)) => Some(Number(f)) - | (I_Numeric, EvDistribution(Symbolic(#Float(f)))) => Some(Number(f)) - | (I_Option(v), _) => Some(Option(matchInput(v, r))) - | (I_Record(recordParams), EvRecord(record)) => { - let getAndMatch = (name, input) => - E.Dict.get(record, name)->E.O.bind(v => matchInput(input, v)) - let arrayOfNameValues: array<(Js.Dict.key, option)> = - recordParams->E.A2.fmap(((name, input)) => (name, getAndMatch(name, input))) - let hasNullValues = E.A.hasBy(arrayOfNameValues, ((_, value)) => E.O.isNone(value)) - if hasNullValues { - None - } else { - arrayOfNameValues - ->E.A2.fmap(((name, value)) => (name, value->E.O2.toExn(""))) - ->(r => Some(Record(r))) +module FRType = { + type t = frType + let rec toString = (t: t) => + switch t { + | FRTypeNumber => "number" + | FRTypeNumeric => "numeric" + | FRTypeDistOrNumber => "frValueDistOrNumber" + | FRTypeRecord(r) => { + let input = ((name, frType): frTypeRecordParam) => `${name}: ${toString(frType)}` + `record({${r->E.A2.fmap(input)->E.A2.joinWith(", ")}})` } + | FRTypeArray(r) => `record(${r->E.A2.fmap(toString)->E.A2.joinWith(", ")})` + | FRTypeOption(v) => `option(${toString(v)})` + } + + let rec matchWithExpressionValue = (input: t, r: expressionValue): option => + switch (input, r) { + | (FRTypeNumber, EvNumber(f)) => Some(FRValueNumber(f)) + | (FRTypeDistOrNumber, EvNumber(f)) => Some(FRValueDistOrNumber(FRValueNumber(f))) + | (FRTypeDistOrNumber, EvDistribution(Symbolic(#Float(f)))) => + Some(FRValueDistOrNumber(FRValueNumber(f))) + | (FRTypeDistOrNumber, EvDistribution(f)) => Some(FRValueDistOrNumber(FRValueDist(f))) + | (FRTypeNumeric, EvNumber(f)) => Some(FRValueNumber(f)) + | (FRTypeNumeric, EvDistribution(Symbolic(#Float(f)))) => Some(FRValueNumber(f)) + | (FRTypeOption(v), _) => Some(FRValueOption(matchWithExpressionValue(v, r))) + | (FRTypeRecord(recordParams), EvRecord(record)) => { + let getAndMatch = (name, input) => + E.Dict.get(record, name)->E.O.bind(matchWithExpressionValue(input)) + //All names in the type must be present. If any are missing, the corresponding + //value will be None, and this function would return None. + let namesAndValues: array> = + recordParams->E.A2.fmap(((name, input)) => + getAndMatch(name, input)->E.O2.fmap(match => (name, match)) + ) + namesAndValues->E.A.O.openIfAllSome->E.O2.fmap(r => FRValueRecord(r)) + } + | _ => None + } + + let matchWithExpressionValueArray = (inputs: array, args: array): option< + array, + > => { + let isSameLength = E.A.length(inputs) == E.A.length(args) + if !isSameLength { + None + } else { + E.A.zip(inputs, args) + ->E.A2.fmap(((input, arg)) => matchWithExpressionValue(input, arg)) + ->E.A.O.openIfAllSome } - | _ => None } +} module Matcher = { module MatchSimple = { @@ -107,19 +130,8 @@ module Matcher = { module FnDefinition = { type definitionMatch = MatchSimple.t - let getArgValues = (f: fnDefinition, args: array): option> => { - let mainInputTypes = f.inputs - if E.A.length(f.inputs) !== E.A.length(args) { - None - } else { - E.A.zip(mainInputTypes, args) - ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) - ->E.A.O.openIfAllSome - } - } - let matchAssumingSameName = (f: fnDefinition, args: array) => { - switch getArgValues(f, args) { + switch FRType.matchWithExpressionValueArray(f.inputs, args) { | Some(_) => MatchSimple.FullMatch | None => MatchSimple.SameNameDifferentArguments } @@ -228,43 +240,37 @@ module Matcher = { module FnDefinition = { type t = fnDefinition - let getArgValues = (t: t, args: array): option> => { - let mainInputTypes = t.inputs - if E.A.length(t.inputs) !== E.A.length(args) { - None - } else { - E.A.zip(mainInputTypes, args) - ->E.A2.fmap(((input, arg)) => matchInput(input, arg)) - ->E.A.O.openIfAllSome - } - } - let defToString = (t: t) => t.inputs->E.A2.fmap(Itype.toString)->E.A2.joinWith(", ") + let defToString = (t: t) => t.inputs->E.A2.fmap(FRType.toString)->E.A2.joinWith(", ") let run = (t: t, args: array) => { - let argValues = getArgValues(t, args) + let argValues = FRType.matchWithExpressionValueArray(t.inputs, args) switch argValues { | Some(values) => t.run(values) - | None => Error("Impossible") + | None => Error("Incorrect Types") } } -} -module Function = { - type definitionId = int - let make = (~name, ~definitions): function => { - name: name, - definitions: definitions, - } - - let makeDefinition = (~name, ~inputs, ~run): fnDefinition => { + let make = (~name, ~inputs, ~run): fnDefinition => { name: name, inputs: inputs, run: run, } } +module Function = { + let make = (~name, ~definitions): function => { + name: name, + definitions: definitions, + } +} + module Registry = { + /* + 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 + called. However, for now, we could just call the registry last. + */ let matchAndRun = (r: registry, fnName: string, args: array) => { let matchToDef = m => Matcher.Registry.matchToDef(r, m) let showNameMatchDefinitions = matches => { diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res index aa2fa4b1..8ef27a6c 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -9,34 +9,37 @@ module Wrappers = { } module Prepare = { - let recordWithTwoArgsToValues = (inputs: array): result, string> => + let recordWithTwoArgsToValues = (inputs: array): result, string> => switch inputs { - | [Record([(_, n1), (_, n2)])] => Ok([n1, n2]) + | [FRValueRecord([(_, n1), (_, n2)])] => Ok([n1, n2]) | _ => Error(impossibleError) } - let twoNumberInputs = (inputs: array): result<(float, float), string> => { + let twoNumberInputs = (inputs: array): result<(float, float), string> => { switch inputs { - | [Number(n1), Number(n2)] => Ok(n1, n2) + | [FRValueNumber(n1), FRValueNumber(n2)] => Ok(n1, n2) | _ => Error(impossibleError) } } - let twoDistOrNumber = (values: array): result<(distOrNumber, distOrNumber), string> => { + let twoDistOrNumber = (values: array): result< + (frValueDistOrNumber, frValueDistOrNumber), + string, + > => { switch values { - | [DistOrNumber(a1), DistOrNumber(a2)] => Ok(a1, a2) + | [FRValueDistOrNumber(a1), FRValueDistOrNumber(a2)] => Ok(a1, a2) | _ => Error(impossibleError) } } - let twoDistOrNumberFromRecord = (values: array) => + let twoDistOrNumberFromRecord = (values: array) => values->recordWithTwoArgsToValues->E.R.bind(twoDistOrNumber) } module Process = { let twoDistsOrNumbersToDist = ( ~fn: ((float, float)) => result, - ~values: (distOrNumber, distOrNumber), + ~values: (frValueDistOrNumber, frValueDistOrNumber), ) => { let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) let sampleSetToExpressionValue = ( @@ -65,10 +68,10 @@ module Process = { } switch values { - | (Number(a1), Number(a2)) => fn((a1, a2))->E.R2.fmap(Wrappers.evDistribution) - | (Dist(a1), Number(a2)) => singleVarSample(a1, r => fn((r, a2))) - | (Number(a1), Dist(a2)) => singleVarSample(a2, r => fn((a1, r))) - | (Dist(a1), Dist(a2)) => { + | (FRValueNumber(a1), FRValueNumber(a2)) => fn((a1, a2))->E.R2.fmap(Wrappers.evDistribution) + | (FRValueDist(a1), FRValueNumber(a2)) => singleVarSample(a1, r => fn((r, a2))) + | (FRValueNumber(a1), FRValueDist(a2)) => singleVarSample(a2, r => fn((a1, r))) + | (FRValueDist(a1), FRValueDist(a2)) => { let altFn = (a, b) => fn((a, b))->mapFnResult let sampleSetResult = E.R.merge(toSampleSet(a1), toSampleSet(a2)) @@ -95,23 +98,23 @@ module TwoArgDist = { r->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) let mkRegular = (name, fn) => { - Function.makeDefinition(~name, ~inputs=[I_DistOrNumber, I_DistOrNumber], ~run=inputs => + FnDefinition.make(~name, ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], ~run=inputs => inputs->Prepare.twoDistOrNumber->process(~fn) ) } let mkDef90th = (name, fn) => { - Function.makeDefinition( + FnDefinition.make( ~name, - ~inputs=[I_Record([("p5", I_DistOrNumber), ("p95", I_DistOrNumber)])], + ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], ~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn), ) } let mkDefMeanStdev = (name, fn) => { - Function.makeDefinition( + FnDefinition.make( ~name, - ~inputs=[I_Record([("mean", I_DistOrNumber), ("stdev", I_DistOrNumber)])], + ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], ~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn), ) } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index fe579f2c..7e77da63 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -52,7 +52,7 @@ let more = [ ), Function.make( ~name="To", - ~definitions=[TwoArgDist.mkRegular("cauchy", twoArgs(SymbolicDist.From90thPercentile.make))], + ~definitions=[TwoArgDist.mkRegular("to", twoArgs(SymbolicDist.From90thPercentile.make))], ) ] diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index afac3bbe..fe00d9bb 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -2,6 +2,9 @@ Some functions from modules `L`, `O`, and `R` below were copied directly from running `rescript convert -all` on Rationale https://github.com/jonlaing/rationale */ + +let equals = (a,b) => a === b + module FloatFloatMap = { module Id = Belt.Id.MakeComparable({ type t = float From 7e2437bfc0a39f0dc32572d9f347db04515a424a Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Fri, 20 May 2022 22:54:15 -0400 Subject: [PATCH 19/26] Prettier --- .../squiggle-lang/src/rescript/Distributions/GenericDist.res | 3 +-- .../src/rescript/FunctionRegistry/FunctionRegistry_Library.res | 2 +- packages/squiggle-lang/src/rescript/Utility/E.res | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res b/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res index dc50833e..d6920a4e 100644 --- a/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res +++ b/packages/squiggle-lang/src/rescript/Distributions/GenericDist.res @@ -24,7 +24,6 @@ let isSymbolic = (t: t) => | _ => false } - let sampleN = (t: t, n) => switch t { | PointSet(r) => PointSetDist.sampleNRendered(n, r) @@ -32,7 +31,7 @@ let sampleN = (t: t, n) => | SampleSet(r) => SampleSetDist.sampleN(r, n) } -let sample = (t: t) => sampleN(t, 1) -> E.A.first |> E.O.toExn("Should not have happened") +let sample = (t: t) => sampleN(t, 1)->E.A.first |> E.O.toExn("Should not have happened") let toSampleSetDist = (t: t, n) => SampleSetDist.make(sampleN(t, n))->E.R2.errMap(DistributionTypes.Error.sampleErrorToDistErr) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 7e77da63..d998191f 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -53,7 +53,7 @@ let more = [ Function.make( ~name="To", ~definitions=[TwoArgDist.mkRegular("to", twoArgs(SymbolicDist.From90thPercentile.make))], - ) + ), ] let allFunctions = [NormalFn.toFn, LognormalFn.toFn] diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index fe00d9bb..1916b8b1 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -3,7 +3,7 @@ Some functions from modules `L`, `O`, and `R` below were copied directly from running `rescript convert -all` on Rationale https://github.com/jonlaing/rationale */ -let equals = (a,b) => a === b +let equals = (a, b) => a === b module FloatFloatMap = { module Id = Belt.Id.MakeComparable({ From 40bf7443c9a0e5e582fa788329912b33079600db Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 21 May 2022 11:41:12 -0400 Subject: [PATCH 20/26] Simple FunctionRegistry cleanup --- .../FunctionRegistry_Core.res | 38 +++++++---- .../FunctionRegistry_Helpers.res | 68 ++++++++++--------- .../FunctionRegistry_Library.res | 4 +- .../squiggle-lang/src/rescript/Utility/E.res | 1 + 4 files changed, 62 insertions(+), 49 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 5e9e877e..fcb27cbe 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -56,8 +56,8 @@ module FRType = { | FRTypeOption(v) => `option(${toString(v)})` } - let rec matchWithExpressionValue = (input: t, r: expressionValue): option => - switch (input, r) { + let rec matchWithExpressionValue = (t: t, r: expressionValue): option => + switch (t, r) { | (FRTypeNumber, EvNumber(f)) => Some(FRValueNumber(f)) | (FRTypeDistOrNumber, EvNumber(f)) => Some(FRValueDistOrNumber(FRValueNumber(f))) | (FRTypeDistOrNumber, EvDistribution(Symbolic(#Float(f)))) => @@ -94,6 +94,11 @@ module FRType = { } } +/* + This module, Matcher, is fairly lengthy. However, only two functions from it + are meant to be used outside of it. These are findMatches and matchToDef in Matches.Registry. + The rest of it is just called from those two functions. +*/ module Matcher = { module MatchSimple = { type t = DifferentName | SameNameDifferentArguments | FullMatch @@ -185,21 +190,18 @@ module Matcher = { } module Registry = { - let findExactMatches = (r: registry, fnName: string, args: array) => { + let _findExactMatches = (r: registry, fnName: string, args: array) => { let functionMatchPairs = r->E.A2.fmap(l => (l, Function.match(l, fnName, args))) - let getFullMatch = E.A.getBy(functionMatchPairs, ((_, match: Function.match)) => - Match.isFullMatch(match) - ) - let fullMatch: option = getFullMatch->E.O.bind(((fn, match)) => + let fullMatch = functionMatchPairs->E.A.getBy(((_, match)) => Match.isFullMatch(match)) + fullMatch->E.O.bind(((fn, match)) => switch match { | FullMatch(index) => Some(RegistryMatch.makeMatch(fn.name, index)) | _ => None } ) - fullMatch } - let findNameMatches = (r: registry, fnName: string, args: array) => { + let _findNameMatches = (r: registry, fnName: string, args: array) => { let functionMatchPairs = r->E.A2.fmap(l => (l, Function.match(l, fnName, args))) let getNameMatches = functionMatchPairs @@ -219,10 +221,10 @@ module Matcher = { } let findMatches = (r: registry, fnName: string, args: array) => { - switch findExactMatches(r, fnName, args) { + switch _findExactMatches(r, fnName, args) { | Some(r) => Match.FullMatch(r) | None => - switch findNameMatches(r, fnName, args) { + switch _findNameMatches(r, fnName, args) { | Some(r) => Match.SameNameDifferentArguments(r) | None => Match.DifferentName } @@ -241,7 +243,10 @@ module Matcher = { module FnDefinition = { type t = fnDefinition - let defToString = (t: t) => t.inputs->E.A2.fmap(FRType.toString)->E.A2.joinWith(", ") + let toString = (t: t) => { + let inputs = t.inputs->E.A2.fmap(FRType.toString)->E.A2.joinWith(", ") + t.name ++ `(${inputs})` + } let run = (t: t, args: array) => { let argValues = FRType.matchWithExpressionValueArray(t.inputs, args) @@ -251,7 +256,7 @@ module FnDefinition = { } } - let make = (~name, ~inputs, ~run): fnDefinition => { + let make = (~name, ~inputs, ~run): t => { name: name, inputs: inputs, run: run, @@ -259,7 +264,9 @@ module FnDefinition = { } module Function = { - let make = (~name, ~definitions): function => { + type t = function + + let make = (~name, ~definitions): t => { name: name, definitions: definitions, } @@ -278,7 +285,8 @@ module Registry = { matches ->E.A2.fmap(matchToDef) ->E.A.O.concatSomes - ->E.A2.fmap(r => `[${fnName}(${FnDefinition.defToString(r)})]`) + ->E.A2.fmap(FnDefinition.toString) + ->E.A2.fmap(r => `[${r}]`) ->E.A2.joinWith("; ") `There are function matches for ${fnName}(), but with different arguments: ${defs}` } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res index 8ef27a6c..6daeace1 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -9,44 +9,43 @@ module Wrappers = { } module Prepare = { - let recordWithTwoArgsToValues = (inputs: array): result, string> => - switch inputs { - | [FRValueRecord([(_, n1), (_, n2)])] => Ok([n1, n2]) - | _ => Error(impossibleError) - } + type ts = array + type err = string - let twoNumberInputs = (inputs: array): result<(float, float), string> => { - switch inputs { - | [FRValueNumber(n1), FRValueNumber(n2)] => Ok(n1, n2) - | _ => Error(impossibleError) + module ToValueArray = { + module Record = { + let twoArgs = (inputs: ts): result => + switch inputs { + | [FRValueRecord([(_, n1), (_, n2)])] => Ok([n1, n2]) + | _ => Error(impossibleError) + } } } - let twoDistOrNumber = (values: array): result< - (frValueDistOrNumber, frValueDistOrNumber), - string, - > => { - switch values { - | [FRValueDistOrNumber(a1), FRValueDistOrNumber(a2)] => Ok(a1, a2) - | _ => Error(impossibleError) + module ToValueTuple = { + let twoDistOrNumber = (values: ts): result<(frValueDistOrNumber, frValueDistOrNumber), err> => { + switch values { + | [FRValueDistOrNumber(a1), FRValueDistOrNumber(a2)] => Ok(a1, a2) + | _ => Error(impossibleError) + } + } + + module Record = { + let twoDistOrNumber = (values: ts): result<(frValueDistOrNumber, frValueDistOrNumber), err> => + values->ToValueArray.Record.twoArgs->E.R.bind(twoDistOrNumber) } } - - let twoDistOrNumberFromRecord = (values: array) => - values->recordWithTwoArgsToValues->E.R.bind(twoDistOrNumber) } module Process = { let twoDistsOrNumbersToDist = ( ~fn: ((float, float)) => result, ~values: (frValueDistOrNumber, frValueDistOrNumber), - ) => { + ): result => { let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) - let sampleSetToExpressionValue = ( - b: Belt.Result.t, - ) => + let sampleSetToExpressionValue = (b: Belt.Result.t) => switch b { - | Ok(r) => Ok(ReducerInterface_ExpressionValue.EvDistribution(SampleSet(r))) + | Ok(r) => Ok(DistributionTypes.SampleSet(r)) | Error(d) => Error(DistributionTypes.Error.toString(d)) } @@ -56,9 +55,11 @@ module Process = { | Error(r) => Error(Operation.Other(r)) } - let singleVarSample = (a, fn) => { + let singleVarSample = (dist, fn) => { let sampleSetResult = - toSampleSet(a) |> E.R2.bind(dist => + dist + ->toSampleSet + ->E.R.bind(dist => SampleSetDist.samplesMap( ~fn=f => fn(f)->mapFnResult, dist, @@ -68,7 +69,7 @@ module Process = { } switch values { - | (FRValueNumber(a1), FRValueNumber(a2)) => fn((a1, a2))->E.R2.fmap(Wrappers.evDistribution) + | (FRValueNumber(a1), FRValueNumber(a2)) => fn((a1, a2)) | (FRValueDist(a1), FRValueNumber(a2)) => singleVarSample(a1, r => fn((r, a2))) | (FRValueNumber(a1), FRValueDist(a2)) => singleVarSample(a2, r => fn((a1, r))) | (FRValueDist(a1), FRValueDist(a2)) => { @@ -89,17 +90,20 @@ module Process = { ~fn: ((float, float)) => result, ~values, ) => { - twoDistsOrNumbersToDist(~fn=r => r->fn->E.R2.fmap(Wrappers.symbolic), ~values) + let newFn = r => fn(r)->E.R2.fmap(Wrappers.symbolic) + twoDistsOrNumbersToDist(~fn=newFn, ~values) } } module TwoArgDist = { let process = (~fn, r) => - r->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) + r + ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) + ->E.R2.fmap(Wrappers.evDistribution) let mkRegular = (name, fn) => { FnDefinition.make(~name, ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], ~run=inputs => - inputs->Prepare.twoDistOrNumber->process(~fn) + inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn) ) } @@ -107,7 +111,7 @@ module TwoArgDist = { FnDefinition.make( ~name, ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], - ~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn), + ~run=inputs => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn), ) } @@ -115,7 +119,7 @@ module TwoArgDist = { FnDefinition.make( ~name, ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], - ~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn), + ~run=inputs => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn), ) } } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index d998191f..705da963 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -1,7 +1,7 @@ open FunctionRegistry_Core open FunctionRegistry_Helpers -let twoArgs = (fn, (a1, a2)) => fn(a1, a2) +let twoArgs = E.Tuple2.toFnCall module NormalFn = { let fnName = "normal" @@ -56,4 +56,4 @@ let more = [ ), ] -let allFunctions = [NormalFn.toFn, LognormalFn.toFn] +let allFunctions = E.A.append([NormalFn.toFn, LognormalFn.toFn], more) diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 1916b8b1..3357f4f4 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -52,6 +52,7 @@ module Tuple2 = { let (_, b) = v b } + let toFnCall = (fn, (a1, a2)) => fn(a1, a2) } module O = { From ce58cf1bb303e57b04042f0202256b534922f8d0 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 21 May 2022 12:09:49 -0400 Subject: [PATCH 21/26] Beginning cleanup of Process errors --- .../FunctionRegistry_Helpers.res | 48 ++++++++----------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res index 6daeace1..fd0acb9b 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -43,12 +43,6 @@ module Process = { ~values: (frValueDistOrNumber, frValueDistOrNumber), ): result => { let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) - let sampleSetToExpressionValue = (b: Belt.Result.t) => - switch b { - | Ok(r) => Ok(DistributionTypes.SampleSet(r)) - | Error(d) => Error(DistributionTypes.Error.toString(d)) - } - let mapFnResult = r => switch r { | Ok(r) => Ok(GenericDist.sample(r)) @@ -56,33 +50,33 @@ module Process = { } let singleVarSample = (dist, fn) => { - let sampleSetResult = - dist - ->toSampleSet - ->E.R.bind(dist => - SampleSetDist.samplesMap( - ~fn=f => fn(f)->mapFnResult, - dist, - )->E.R2.errMap(r => DistributionTypes.SampleSetError(r)) - ) - sampleSetResult->sampleSetToExpressionValue + switch toSampleSet(dist) { + | Ok(dist) => + switch SampleSetDist.samplesMap(~fn=f => fn(f)->mapFnResult, dist) { + | Ok(r) => Ok(DistributionTypes.SampleSet(r)) + | Error(r) => Error(DistributionTypes.Error.toString(DistributionTypes.SampleSetError(r))) + } + | Error(r) => Error(DistributionTypes.Error.toString(r)) + } + } + + let twoVarSample = (dist1, dist2, fn) => { + let altFn = (a, b) => fn((a, b))->mapFnResult + switch E.R.merge(toSampleSet(dist1), toSampleSet(dist2)) { + | Ok((t1, t2)) => + switch SampleSetDist.map2(~fn=altFn, ~t1, ~t2) { + | Ok(r) => Ok(DistributionTypes.SampleSet(r)) + | Error(r) => Error(Operation.Error.toString(r)) + } + | Error(r) => Error(DistributionTypes.Error.toString(r)) + } } switch values { | (FRValueNumber(a1), FRValueNumber(a2)) => fn((a1, a2)) | (FRValueDist(a1), FRValueNumber(a2)) => singleVarSample(a1, r => fn((r, a2))) | (FRValueNumber(a1), FRValueDist(a2)) => singleVarSample(a2, r => fn((a1, r))) - | (FRValueDist(a1), FRValueDist(a2)) => { - let altFn = (a, b) => fn((a, b))->mapFnResult - let sampleSetResult = - E.R.merge(toSampleSet(a1), toSampleSet(a2)) - ->E.R2.errMap(DistributionTypes.Error.toString) - ->E.R.bind(((t1, t2)) => { - SampleSetDist.map2(~fn=altFn, ~t1, ~t2)->E.R2.errMap(Operation.Error.toString) - }) - ->E.R2.errMap(r => DistributionTypes.OtherError(r)) - sampleSetResult->sampleSetToExpressionValue - } + | (FRValueDist(a1), FRValueDist(a2)) => twoVarSample(a1, a2, fn) } } From 3531005a2b8eab07985e0a3950e62ec1bc6e0339 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 21 May 2022 12:18:54 -0400 Subject: [PATCH 22/26] Added enviornment to Function Registry --- .../FunctionRegistry/FunctionRegistry_Core.res | 15 ++++++++++----- .../FunctionRegistry/FunctionRegistry_Helpers.res | 15 ++++++++------- .../ReducerInterface_GenericDistribution.res | 6 +++--- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index fcb27cbe..3559fb5c 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -31,7 +31,7 @@ and frValueDistOrNumber = FRValueNumber(float) | FRValueDist(DistributionTypes.g type fnDefinition = { name: string, inputs: array, - run: array => result, + run: (array, DistributionOperation.env) => result, } type function = { @@ -248,10 +248,10 @@ module FnDefinition = { t.name ++ `(${inputs})` } - let run = (t: t, args: array) => { + let run = (t: t, args: array, env: DistributionOperation.env) => { let argValues = FRType.matchWithExpressionValueArray(t.inputs, args) switch argValues { - | Some(values) => t.run(values) + | Some(values) => t.run(values, env) | None => Error("Incorrect Types") } } @@ -278,7 +278,12 @@ 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 = (r: registry, fnName: string, args: array) => { + let matchAndRun = ( + r: registry, + fnName: string, + args: array, + env: DistributionOperation.env, + ) => { let matchToDef = m => Matcher.Registry.matchToDef(r, m) let showNameMatchDefinitions = matches => { let defs = @@ -291,7 +296,7 @@ module Registry = { `There are function matches for ${fnName}(), but with different arguments: ${defs}` } switch Matcher.Registry.findMatches(r, fnName, args) { - | Matcher.Match.FullMatch(match) => match->matchToDef->E.O2.fmap(FnDefinition.run(_, 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_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res index fd0acb9b..799d119c 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -41,8 +41,9 @@ module Process = { let twoDistsOrNumbersToDist = ( ~fn: ((float, float)) => result, ~values: (frValueDistOrNumber, frValueDistOrNumber), + ~env: DistributionOperation.env, ): result => { - let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) + let toSampleSet = r => GenericDist.toSampleSetDist(r, env.sampleCount) let mapFnResult = r => switch r { | Ok(r) => Ok(GenericDist.sample(r)) @@ -90,14 +91,14 @@ module Process = { } module TwoArgDist = { - let process = (~fn, r) => + let process = (~fn, ~env, r) => r - ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) + ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_, ~env)) ->E.R2.fmap(Wrappers.evDistribution) let mkRegular = (name, fn) => { - FnDefinition.make(~name, ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], ~run=inputs => - inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn) + FnDefinition.make(~name, ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], ~run=(inputs, env) => + inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env) ) } @@ -105,7 +106,7 @@ module TwoArgDist = { FnDefinition.make( ~name, ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], - ~run=inputs => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn), + ~run=(inputs, env) => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), ) } @@ -113,7 +114,7 @@ module TwoArgDist = { FnDefinition.make( ~name, ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], - ~run=inputs => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn), + ~run=(inputs, env) => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), ) } } diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index 714ad47b..d7aaeee9 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -363,8 +363,8 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result< let registered = FunctionRegistry_Library.allFunctions -let tryRegistry = ((fnName, args): ExpressionValue.functionCall) => { - FunctionRegistry_Core.Registry.matchAndRun(registered, fnName, args)->E.O2.fmap( +let tryRegistry = ((fnName, args): ExpressionValue.functionCall, env) => { + FunctionRegistry_Core.Registry.matchAndRun(registered, fnName, args, env)->E.O2.fmap( E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), ) } @@ -374,6 +374,6 @@ let dispatch = (call: ExpressionValue.functionCall, environment) => { dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue) switch regularDispatch { | Some(x) => Some(x) - | None => tryRegistry(call) + | None => tryRegistry(call, environment) } } From c200259c79265bf555997960d69a768bb03ca0fa Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sat, 21 May 2022 13:52:17 -0400 Subject: [PATCH 23/26] Added simpe README and resi for FunctionRegistry --- .../FunctionRegistry_Core.res | 12 ++-- .../FunctionRegistry_Core.resi | 59 +++++++++++++++++++ .../FunctionRegistry_Helpers.res | 1 + .../src/rescript/FunctionRegistry/README.md | 46 +++++++++++++++ .../ReducerInterface_GenericDistribution.res | 4 +- 5 files changed, 114 insertions(+), 8 deletions(-) create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.resi create mode 100644 packages/squiggle-lang/src/rescript/FunctionRegistry/README.md diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 3559fb5c..92c575f0 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -279,12 +279,12 @@ module Registry = { called. However, for now, we could just call the registry last. */ let matchAndRun = ( - r: registry, - fnName: string, - args: array, - env: DistributionOperation.env, + ~registry: registry, + ~fnName: string, + ~args: array, + ~env: DistributionOperation.env, ) => { - let matchToDef = m => Matcher.Registry.matchToDef(r, m) + let matchToDef = m => Matcher.Registry.matchToDef(registry, m) let showNameMatchDefinitions = matches => { let defs = matches @@ -295,7 +295,7 @@ module Registry = { ->E.A2.joinWith("; ") `There are function matches for ${fnName}(), but with different arguments: ${defs}` } - switch Matcher.Registry.findMatches(r, fnName, args) { + switch Matcher.Registry.findMatches(registry, 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_Core.resi b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.resi new file mode 100644 index 00000000..55c060be --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.resi @@ -0,0 +1,59 @@ +type expressionValue = ReducerInterface_ExpressionValue.expressionValue + +type rec frType = + | FRTypeNumber + | FRTypeNumeric + | FRTypeDistOrNumber + | FRTypeRecord(frTypeRecord) + | FRTypeArray(array) + | FRTypeOption(frType) +and frTypeRecord = array +and frTypeRecordParam = (string, frType) + +type rec frValue = + | FRValueNumber(float) + | FRValueDist(DistributionTypes.genericDist) + | FRValueOption(option) + | FRValueDistOrNumber(frValueDistOrNumber) + | FRValueRecord(frValueRecord) +and frValueRecord = array +and frValueRecordParam = (string, frValue) +and frValueDistOrNumber = FRValueNumber(float) | FRValueDist(DistributionTypes.genericDist) + +type fnDefinition = { + name: string, + inputs: array, + run: (array, DistributionOperation.env) => result, +} + +type function = { + name: string, + definitions: array, +} + +type registry = array + + +// Note: The function "name" is just used for documentation purposes +module Function: { + type t = function + let make: (~name: string, ~definitions: array) => t +} + +module FnDefinition: { + type t = fnDefinition + let make: ( + ~name: string, + ~inputs: array, + ~run: (array, DistributionOperation.env) => result, + ) => t +} + +module Registry: { + let matchAndRun: ( + ~registry: registry, + ~fnName: string, + ~args: array, + ~env: QuriSquiggleLang.DistributionOperation.env, + ) => option> +} diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res index 799d119c..a9644756 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -117,4 +117,5 @@ module TwoArgDist = { ~run=(inputs, env) => inputs->Prepare.ToValueTuple.Record.twoDistOrNumber->process(~fn, ~env), ) } + } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/README.md b/packages/squiggle-lang/src/rescript/FunctionRegistry/README.md new file mode 100644 index 00000000..3bdc387a --- /dev/null +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/README.md @@ -0,0 +1,46 @@ +# Function Registry + +The function registry is a library for organizing function definitions. + +The main interface is fairly constrained. Basically, write functions like the following, and add them to a big array. + +```rescript + Function.make( + ~name="Normal", + ~definitions=[ + FnDefinition.make( + ~name="Normal", + ~definitions=[ + FnDefinition.make(~name="normal", ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], ~run=( + inputs, + env, + ) => + inputs + ->Prepare.ToValueTuple.twoDistOrNumber + ->E.R.bind( + Process.twoDistsOrNumbersToDistUsingSymbolicDist( + ~fn=E.Tuple2.toFnCall(SymbolicDist.Normal.make), + ~env, + ~values=_, + ), + ) + ->E.R2.fmap(Wrappers.evDistribution) + ), + ], + ) + ], + ) +``` + +The Function name is just there for future documentation. The function defintions + +## Key Files + +**FunctionRegistry_Core** +Key types, internal functionality, and a ``Registry`` module with a ``matchAndRun`` function to call function definitions. + +**FunctionRegistry_Library** +A list of all the Functions defined in the Function Registry. + +**FunctionRegistry_Helpers** +A list of helper functions for the FunctionRegistry_Library. \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index d7aaeee9..c8aeb01c 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -361,10 +361,10 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result< | GenDistError(err) => Error(REDistributionError(err)) } -let registered = FunctionRegistry_Library.allFunctions +let registry = FunctionRegistry_Library.allFunctions let tryRegistry = ((fnName, args): ExpressionValue.functionCall, env) => { - FunctionRegistry_Core.Registry.matchAndRun(registered, fnName, args, env)->E.O2.fmap( + FunctionRegistry_Core.Registry.matchAndRun(~registry, ~fnName, ~args, ~env)->E.O2.fmap( E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)), ) } From ee94a054d0dc968ca6ec2474b9c8d52279b5db6f Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Sun, 22 May 2022 10:38:17 -0400 Subject: [PATCH 24/26] Minor cleanup --- .../FunctionRegistry_Helpers.res | 6 +-- .../FunctionRegistry_Library.res | 48 ++++++++----------- .../ReducerInterface_GenericDistribution.res | 3 +- 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res index a9644756..f7184704 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -96,13 +96,13 @@ module TwoArgDist = { ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_, ~env)) ->E.R2.fmap(Wrappers.evDistribution) - let mkRegular = (name, fn) => { + let make = (name, fn) => { FnDefinition.make(~name, ~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber], ~run=(inputs, env) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env) ) } - let mkDef90th = (name, fn) => { + let makeRecordP5P95 = (name, fn) => { FnDefinition.make( ~name, ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])], @@ -110,7 +110,7 @@ module TwoArgDist = { ) } - let mkDefMeanStdev = (name, fn) => { + let makeRecordMeanStdev = (name, fn) => { FnDefinition.make( ~name, ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])], diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 705da963..1fca69bf 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -3,57 +3,47 @@ open FunctionRegistry_Helpers let twoArgs = E.Tuple2.toFnCall -module NormalFn = { - let fnName = "normal" - - let toFn = Function.make( +let registry = [ + Function.make( ~name="Normal", ~definitions=[ - TwoArgDist.mkRegular(fnName, twoArgs(SymbolicDist.Normal.make)), - TwoArgDist.mkDef90th(fnName, r => twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok), - TwoArgDist.mkDefMeanStdev(fnName, twoArgs(SymbolicDist.Normal.make)), + TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), + TwoArgDist.makeRecordP5P95("normal", r => twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok), + TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), ], - ) -} - -module LognormalFn = { - let fnName = "lognormal" - - let toFn = Function.make( + ), + Function.make( ~name="Lognormal", ~definitions=[ - TwoArgDist.mkRegular(fnName, twoArgs(SymbolicDist.Lognormal.make)), - TwoArgDist.mkDef90th(fnName, r => twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok), - TwoArgDist.mkDefMeanStdev(fnName, twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev)), + TwoArgDist.make("lognormal", twoArgs(SymbolicDist.Lognormal.make)), + TwoArgDist.makeRecordP5P95("lognormal", r => + twoArgs(SymbolicDist.Lognormal.from90PercentCI, r)->Ok + ), + TwoArgDist.makeRecordMeanStdev("lognormal", twoArgs(SymbolicDist.Lognormal.fromMeanAndStdev)), ], - ) -} - -let more = [ + ), Function.make( ~name="Uniform", - ~definitions=[TwoArgDist.mkRegular("uniform", twoArgs(SymbolicDist.Uniform.make))], + ~definitions=[TwoArgDist.make("uniform", twoArgs(SymbolicDist.Uniform.make))], ), Function.make( ~name="Beta", - ~definitions=[TwoArgDist.mkRegular("beta", twoArgs(SymbolicDist.Beta.make))], + ~definitions=[TwoArgDist.make("beta", twoArgs(SymbolicDist.Beta.make))], ), Function.make( ~name="Cauchy", - ~definitions=[TwoArgDist.mkRegular("cauchy", twoArgs(SymbolicDist.Cauchy.make))], + ~definitions=[TwoArgDist.make("cauchy", twoArgs(SymbolicDist.Cauchy.make))], ), Function.make( ~name="Gamma", - ~definitions=[TwoArgDist.mkRegular("gamma", twoArgs(SymbolicDist.Gamma.make))], + ~definitions=[TwoArgDist.make("gamma", twoArgs(SymbolicDist.Gamma.make))], ), Function.make( ~name="Logistic", - ~definitions=[TwoArgDist.mkRegular("logistic", twoArgs(SymbolicDist.Logistic.make))], + ~definitions=[TwoArgDist.make("logistic", twoArgs(SymbolicDist.Logistic.make))], ), Function.make( ~name="To", - ~definitions=[TwoArgDist.mkRegular("to", twoArgs(SymbolicDist.From90thPercentile.make))], + ~definitions=[TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make))], ), ] - -let allFunctions = E.A.append([NormalFn.toFn, LognormalFn.toFn], more) diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index c8aeb01c..dfb3d745 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -361,7 +361,8 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result< | GenDistError(err) => Error(REDistributionError(err)) } -let registry = FunctionRegistry_Library.allFunctions +// 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): ExpressionValue.functionCall, env) => { FunctionRegistry_Core.Registry.matchAndRun(~registry, ~fnName, ~args, ~env)->E.O2.fmap( From 054e37959382f8dab494b5f22e131cbd1072c0d5 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 23 May 2022 13:47:54 -0400 Subject: [PATCH 25/26] Fixed test --- .../ReducerInterface/ReducerInterface_Distribution_test.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res index 48bdcaa5..15beced4 100644 --- a/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res +++ b/packages/squiggle-lang/__tests__/ReducerInterface/ReducerInterface_Distribution_test.res @@ -23,7 +23,7 @@ describe("eval on distribution functions", () => { testEval("-normal(5,2)", "Ok(Normal(-5,2))") }) describe("to", () => { - testEval("5 to 2", "Error(Distribution Math Error: Low value must be less than high value.)") + testEval("5 to 2", "Error(TODO: Low value must be less than high value.)") testEval("to(2,5)", "Ok(Lognormal(1.1512925464970227,0.27853260523016377))") testEval("to(-2,2)", "Ok(Normal(0,1.2159136638235384))") }) From 003b320acb826bd84d56b590fdfecaf3b977eac5 Mon Sep 17 00:00:00 2001 From: Ozzie Gooen Date: Mon, 23 May 2022 14:28:32 -0400 Subject: [PATCH 26/26] Fixing lint and tests --- .../FunctionRegistry_Core.res | 3 - .../FunctionRegistry_Core.resi | 1 - .../FunctionRegistry_Helpers.res | 121 +++++++++++------- .../FunctionRegistry_Library.res | 21 ++- .../src/rescript/FunctionRegistry/README.md | 4 +- .../ReducerInterface_GenericDistribution.res | 11 -- 6 files changed, 97 insertions(+), 64 deletions(-) diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res index 92c575f0..99ecc78f 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.res @@ -133,8 +133,6 @@ module Matcher = { } module FnDefinition = { - type definitionMatch = MatchSimple.t - let matchAssumingSameName = (f: fnDefinition, args: array) => { switch FRType.matchWithExpressionValueArray(f.inputs, args) { | Some(_) => MatchSimple.FullMatch @@ -185,7 +183,6 @@ module Matcher = { fnName: string, inputIndex: int, } - type t = Match.t, match> let makeMatch = (fnName: string, inputIndex: int) => {fnName: fnName, inputIndex: inputIndex} } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.resi b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.resi index 55c060be..5ca8c708 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.resi +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Core.resi @@ -33,7 +33,6 @@ type function = { type registry = array - // Note: The function "name" is just used for documentation purposes module Function: { type t = function diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res index f7184704..118a15d2 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Helpers.res @@ -5,7 +5,7 @@ let impossibleError = "Wrong inputs / Logically impossible" module Wrappers = { let symbolic = r => DistributionTypes.Symbolic(r) let evDistribution = r => ReducerInterface_ExpressionValue.EvDistribution(r) - let symbolicEvDistribution = r => r->Symbolic->evDistribution + let symbolicEvDistribution = r => r->DistributionTypes.Symbolic->evDistribution } module Prepare = { @@ -30,6 +30,13 @@ module Prepare = { } } + let oneDistOrNumber = (values: ts): result => { + switch values { + | [FRValueDistOrNumber(a1)] => Ok(a1) + | _ => Error(impossibleError) + } + } + module Record = { let twoDistOrNumber = (values: ts): result<(frValueDistOrNumber, frValueDistOrNumber), err> => values->ToValueArray.Record.twoArgs->E.R.bind(twoDistOrNumber) @@ -38,62 +45,78 @@ module Prepare = { } module Process = { - let twoDistsOrNumbersToDist = ( - ~fn: ((float, float)) => result, - ~values: (frValueDistOrNumber, frValueDistOrNumber), - ~env: DistributionOperation.env, - ): result => { - let toSampleSet = r => GenericDist.toSampleSetDist(r, env.sampleCount) - let mapFnResult = r => - switch r { - | Ok(r) => Ok(GenericDist.sample(r)) - | Error(r) => Error(Operation.Other(r)) - } + module DistOrNumberToDist = { + module Helpers = { + let toSampleSet = (r, env: DistributionOperation.env) => + GenericDist.toSampleSetDist(r, env.sampleCount) - let singleVarSample = (dist, fn) => { - switch toSampleSet(dist) { - | Ok(dist) => - switch SampleSetDist.samplesMap(~fn=f => fn(f)->mapFnResult, dist) { - | Ok(r) => Ok(DistributionTypes.SampleSet(r)) - | Error(r) => Error(DistributionTypes.Error.toString(DistributionTypes.SampleSetError(r))) + let mapFnResult = r => + switch r { + | Ok(r) => Ok(GenericDist.sample(r)) + | Error(r) => Error(Operation.Other(r)) } - | Error(r) => Error(DistributionTypes.Error.toString(r)) - } - } - let twoVarSample = (dist1, dist2, fn) => { - let altFn = (a, b) => fn((a, b))->mapFnResult - switch E.R.merge(toSampleSet(dist1), toSampleSet(dist2)) { - | Ok((t1, t2)) => - switch SampleSetDist.map2(~fn=altFn, ~t1, ~t2) { - | Ok(r) => Ok(DistributionTypes.SampleSet(r)) - | Error(r) => Error(Operation.Error.toString(r)) + let wrapSymbolic = (fn, r) => r->fn->E.R2.fmap(Wrappers.symbolic) + + let singleVarSample = (dist, fn, env) => { + switch toSampleSet(dist, env) { + | Ok(dist) => + switch SampleSetDist.samplesMap(~fn=f => fn(f)->mapFnResult, dist) { + | Ok(r) => Ok(DistributionTypes.SampleSet(r)) + | Error(r) => Error(DistributionTypes.Error.toString(DistributionTypes.SampleSetError(r))) + } + | Error(r) => Error(DistributionTypes.Error.toString(r)) + } + } + + let twoVarSample = (dist1, dist2, fn, env) => { + let altFn = (a, b) => fn((a, b))->mapFnResult + switch E.R.merge(toSampleSet(dist1, env), toSampleSet(dist2, env)) { + | Ok((t1, t2)) => + switch SampleSetDist.map2(~fn=altFn, ~t1, ~t2) { + | Ok(r) => Ok(DistributionTypes.SampleSet(r)) + | Error(r) => Error(Operation.Error.toString(r)) + } + | Error(r) => Error(DistributionTypes.Error.toString(r)) } - | Error(r) => Error(DistributionTypes.Error.toString(r)) } } - switch values { - | (FRValueNumber(a1), FRValueNumber(a2)) => fn((a1, a2)) - | (FRValueDist(a1), FRValueNumber(a2)) => singleVarSample(a1, r => fn((r, a2))) - | (FRValueNumber(a1), FRValueDist(a2)) => singleVarSample(a2, r => fn((a1, r))) - | (FRValueDist(a1), FRValueDist(a2)) => twoVarSample(a1, a2, fn) + let oneValue = ( + ~fn: float => result, + ~value: frValueDistOrNumber, + ~env: DistributionOperation.env, + ): result => { + switch value { + | FRValueNumber(a1) => fn(a1) + | FRValueDist(a1) => Helpers.singleVarSample(a1, r => fn(r), env) + } } - } - let twoDistsOrNumbersToDistUsingSymbolicDist = ( - ~fn: ((float, float)) => result, - ~values, - ) => { - let newFn = r => fn(r)->E.R2.fmap(Wrappers.symbolic) - twoDistsOrNumbersToDist(~fn=newFn, ~values) + let oneValueUsingSymbolicDist = (~fn, ~value) => oneValue(~fn=Helpers.wrapSymbolic(fn), ~value) + + let twoValues = ( + ~fn: ((float, float)) => result, + ~values: (frValueDistOrNumber, frValueDistOrNumber), + ~env: DistributionOperation.env, + ): result => { + switch values { + | (FRValueNumber(a1), FRValueNumber(a2)) => fn((a1, a2)) + | (FRValueDist(a1), FRValueNumber(a2)) => Helpers.singleVarSample(a1, r => fn((r, a2)), env) + | (FRValueNumber(a1), FRValueDist(a2)) => Helpers.singleVarSample(a2, r => fn((a1, r)), env) + | (FRValueDist(a1), FRValueDist(a2)) => Helpers.twoVarSample(a1, a2, fn, env) + } + } + + let twoValuesUsingSymbolicDist = (~fn, ~values) => + twoValues(~fn=Helpers.wrapSymbolic(fn), ~values) } } module TwoArgDist = { let process = (~fn, ~env, r) => r - ->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_, ~env)) + ->E.R.bind(Process.DistOrNumberToDist.twoValuesUsingSymbolicDist(~fn, ~values=_, ~env)) ->E.R2.fmap(Wrappers.evDistribution) let make = (name, fn) => { @@ -117,5 +140,17 @@ module TwoArgDist = { ~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) + ) + } } diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res index 98f739b3..43be7118 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/FunctionRegistry_Library.res @@ -8,7 +8,9 @@ let registry = [ ~name="Normal", ~definitions=[ TwoArgDist.make("normal", twoArgs(SymbolicDist.Normal.make)), - TwoArgDist.makeRecordP5P95("normal", r => twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok), + TwoArgDist.makeRecordP5P95("normal", r => + twoArgs(SymbolicDist.Normal.from90PercentCI, r)->Ok + ), TwoArgDist.makeRecordMeanStdev("normal", twoArgs(SymbolicDist.Normal.make)), ], ), @@ -44,9 +46,20 @@ let registry = [ ), Function.make( ~name="To", - ~definitions=[TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), - TwoArgDist.make("credibleIntervalToDistribution", twoArgs(SymbolicDist.From90thPercentile.make)) + ~definitions=[ + TwoArgDist.make("to", twoArgs(SymbolicDist.From90thPercentile.make)), + TwoArgDist.make( + "credibleIntervalToDistribution", + twoArgs(SymbolicDist.From90thPercentile.make), + ), ], - + ), + Function.make( + ~name="Exponential", + ~definitions=[OneArgDist.make("exponential", SymbolicDist.Exponential.make)], + ), + Function.make( + ~name="Bernoulli", + ~definitions=[OneArgDist.make("bernoulli", SymbolicDist.Bernoulli.make)], ), ] diff --git a/packages/squiggle-lang/src/rescript/FunctionRegistry/README.md b/packages/squiggle-lang/src/rescript/FunctionRegistry/README.md index 3bdc387a..e974b189 100644 --- a/packages/squiggle-lang/src/rescript/FunctionRegistry/README.md +++ b/packages/squiggle-lang/src/rescript/FunctionRegistry/README.md @@ -37,10 +37,10 @@ The Function name is just there for future documentation. The function defintion ## Key Files **FunctionRegistry_Core** -Key types, internal functionality, and a ``Registry`` module with a ``matchAndRun`` function to call function definitions. +Key types, internal functionality, and a `Registry` module with a `matchAndRun` function to call function definitions. **FunctionRegistry_Library** A list of all the Functions defined in the Function Registry. **FunctionRegistry_Helpers** -A list of helper functions for the FunctionRegistry_Library. \ No newline at end of file +A list of helper functions for the FunctionRegistry_Library. diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res index dfb3d745..dc827805 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_GenericDistribution.res @@ -179,13 +179,6 @@ module Helpers = { } module SymbolicConstructors = { - let oneFloat = name => - switch name { - | "exponential" => Ok(SymbolicDist.Exponential.make) - | "bernoulli" => Ok(SymbolicDist.Bernoulli.make) - | _ => Error("Unreachable state") - } - let threeFloat = name => switch name { | "triangular" => Ok(SymbolicDist.Triangular.make) @@ -207,10 +200,6 @@ let dispatchToGenericOutput = ( ): option => { let (fnName, args) = call switch (fnName, args) { - | (("exponential" | "bernoulli") as fnName, [EvNumber(f)]) => - SymbolicConstructors.oneFloat(fnName) - ->E.R.bind(r => r(f)) - ->SymbolicConstructors.symbolicResultToOutput | ("delta", [EvNumber(f)]) => SymbolicDist.Float.makeSafe(f)->SymbolicConstructors.symbolicResultToOutput | ("triangular" as fnName, [EvNumber(f1), EvNumber(f2), EvNumber(f3)]) =>