Renamed itype->frType, value-> frValue

This commit is contained in:
Ozzie Gooen 2022-05-20 22:53:53 -04:00
parent c9d6302cbf
commit 390ac2e2bb
4 changed files with 121 additions and 109 deletions

View File

@ -1,42 +1,38 @@
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(", ")}})`
/*
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>,
}
| 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)
| 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,
@ -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 => {

View File

@ -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),
)
}

View File

@ -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))],
)
]

View File

@ -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