Renamed itype->frType, value-> frValue
This commit is contained in:
parent
c9d6302cbf
commit
390ac2e2bb
|
@ -1,43 +1,39 @@
|
|||
type expressionValue = ReducerInterface_ExpressionValue.expressionValue
|
||||
|
||||
type rec itype =
|
||||
| I_Number
|
||||
| I_Numeric
|
||||
| I_DistOrNumber
|
||||
| I_Record(iRecord)
|
||||
| I_Array(array<itype>)
|
||||
| I_Option(itype)
|
||||
and iRecord = array<iRecordParam>
|
||||
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<frType>)
|
||||
| FRTypeOption(frType)
|
||||
and frTypeRecord = array<frTypeRecordParam>
|
||||
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<frValue>)
|
||||
| FRValueDistOrNumber(frValueDistOrNumber)
|
||||
| FRValueRecord(frValueRecord)
|
||||
and frValueRecord = array<frValueRecordParam>
|
||||
and frValueRecordParam = (string, frValue)
|
||||
and frValueDistOrNumber = FRValueNumber(float) | FRValueDist(DistributionTypes.genericDist)
|
||||
|
||||
type fnDefinition = {
|
||||
name: string,
|
||||
inputs: array<frType>,
|
||||
run: array<frValue> => result<expressionValue, string>,
|
||||
}
|
||||
|
||||
type rec value =
|
||||
| Number(float)
|
||||
| Dist(DistributionTypes.genericDist)
|
||||
| Option(option<value>)
|
||||
| DistOrNumber(distOrNumber)
|
||||
| Record(record)
|
||||
and record = array<(string, value)>
|
||||
and distOrNumber = Number(float) | Dist(DistributionTypes.genericDist)
|
||||
|
||||
type runFn = array<value> => result<expressionValue, string>
|
||||
|
||||
type fnDefinition = {name: string, inputs: array<itype>, run: runFn}
|
||||
|
||||
type function = {
|
||||
name: string,
|
||||
definitions: array<fnDefinition>,
|
||||
|
@ -45,32 +41,59 @@ type function = {
|
|||
|
||||
type registry = array<function>
|
||||
|
||||
let rec matchInput = (input: itype, r: expressionValue): option<value> =>
|
||||
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<value>)> =
|
||||
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<frValue> =>
|
||||
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<option<(Js.Dict.key, frValue)>> =
|
||||
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<t>, args: array<expressionValue>): option<
|
||||
array<frValue>,
|
||||
> => {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Matcher = {
|
||||
module MatchSimple = {
|
||||
type t = DifferentName | SameNameDifferentArguments | FullMatch
|
||||
|
@ -107,19 +130,8 @@ module Matcher = {
|
|||
module FnDefinition = {
|
||||
type definitionMatch = MatchSimple.t
|
||||
|
||||
let getArgValues = (f: fnDefinition, args: array<expressionValue>): option<array<value>> => {
|
||||
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<expressionValue>) => {
|
||||
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<expressionValue>): option<array<value>> => {
|
||||
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<expressionValue>) => {
|
||||
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<expressionValue>) => {
|
||||
let matchToDef = m => Matcher.Registry.matchToDef(r, m)
|
||||
let showNameMatchDefinitions = matches => {
|
||||
|
|
|
@ -9,34 +9,37 @@ module Wrappers = {
|
|||
}
|
||||
|
||||
module Prepare = {
|
||||
let recordWithTwoArgsToValues = (inputs: array<value>): result<array<value>, string> =>
|
||||
let recordWithTwoArgsToValues = (inputs: array<frValue>): result<array<frValue>, string> =>
|
||||
switch inputs {
|
||||
| [Record([(_, n1), (_, n2)])] => Ok([n1, n2])
|
||||
| [FRValueRecord([(_, n1), (_, n2)])] => Ok([n1, n2])
|
||||
| _ => Error(impossibleError)
|
||||
}
|
||||
|
||||
let twoNumberInputs = (inputs: array<value>): result<(float, float), string> => {
|
||||
let twoNumberInputs = (inputs: array<frValue>): 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<value>): result<(distOrNumber, distOrNumber), string> => {
|
||||
let twoDistOrNumber = (values: array<frValue>): 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<value>) =>
|
||||
let twoDistOrNumberFromRecord = (values: array<frValue>) =>
|
||||
values->recordWithTwoArgsToValues->E.R.bind(twoDistOrNumber)
|
||||
}
|
||||
|
||||
module Process = {
|
||||
let twoDistsOrNumbersToDist = (
|
||||
~fn: ((float, float)) => result<DistributionTypes.genericDist, string>,
|
||||
~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),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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))],
|
||||
)
|
||||
]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user