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,43 +1,39 @@
type expressionValue = ReducerInterface_ExpressionValue.expressionValue type expressionValue = ReducerInterface_ExpressionValue.expressionValue
type rec itype = /*
| I_Number Function Registry "Type". A type, without any other information.
| I_Numeric Like, #Float
| I_DistOrNumber */
| I_Record(iRecord) type rec frType =
| I_Array(array<itype>) | FRTypeNumber
| I_Option(itype) | FRTypeNumeric
and iRecord = array<iRecordParam> | FRTypeDistOrNumber
and iRecordParam = (string, itype) | FRTypeRecord(frTypeRecord)
| FRTypeArray(array<frType>)
| FRTypeOption(frType)
and frTypeRecord = array<frTypeRecordParam>
and frTypeRecordParam = (string, frType)
module Itype = { /*
let rec toString = (t: itype) => Function Registry "Value". A type, with the information of that type.
switch t { Like, #Float(40.0)
| I_Number => "number" */
| I_Numeric => "numeric" type rec frValue =
| I_DistOrNumber => "distOrNumber" | FRValueNumber(float)
| I_Record(r) => { | FRValueDist(DistributionTypes.genericDist)
let input = ((name, itype): iRecordParam) => `${name}: ${toString(itype)}` | FRValueOption(option<frValue>)
`record({${r->E.A2.fmap(input)->E.A2.joinWith(", ")}})` | FRValueDistOrNumber(frValueDistOrNumber)
} | FRValueRecord(frValueRecord)
| I_Array(r) => `record(${r->E.A2.fmap(toString)->E.A2.joinWith(", ")})` and frValueRecord = array<frValueRecordParam>
| I_Option(v) => `option(${toString(v)})` 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 = { type function = {
name: string, name: string,
definitions: array<fnDefinition>, definitions: array<fnDefinition>,
@ -45,31 +41,58 @@ type function = {
type registry = array<function> type registry = array<function>
let rec matchInput = (input: itype, r: expressionValue): option<value> => module FRType = {
switch (input, r) { type t = frType
| (I_Number, EvNumber(f)) => Some(Number(f)) let rec toString = (t: t) =>
| (I_DistOrNumber, EvNumber(f)) => Some(DistOrNumber(Number(f))) switch t {
| (I_DistOrNumber, EvDistribution(Symbolic(#Float(f)))) => Some(DistOrNumber(Number(f))) | FRTypeNumber => "number"
| (I_DistOrNumber, EvDistribution(f)) => Some(DistOrNumber(Dist(f))) | FRTypeNumeric => "numeric"
| (I_Numeric, EvNumber(f)) => Some(Number(f)) | FRTypeDistOrNumber => "frValueDistOrNumber"
| (I_Numeric, EvDistribution(Symbolic(#Float(f)))) => Some(Number(f)) | FRTypeRecord(r) => {
| (I_Option(v), _) => Some(Option(matchInput(v, r))) let input = ((name, frType): frTypeRecordParam) => `${name}: ${toString(frType)}`
| (I_Record(recordParams), EvRecord(record)) => { `record({${r->E.A2.fmap(input)->E.A2.joinWith(", ")}})`
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)))
} }
| 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
} }
| _ => None
} }
}
module Matcher = { module Matcher = {
module MatchSimple = { module MatchSimple = {
@ -107,19 +130,8 @@ module Matcher = {
module FnDefinition = { module FnDefinition = {
type definitionMatch = MatchSimple.t 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>) => { let matchAssumingSameName = (f: fnDefinition, args: array<expressionValue>) => {
switch getArgValues(f, args) { switch FRType.matchWithExpressionValueArray(f.inputs, args) {
| Some(_) => MatchSimple.FullMatch | Some(_) => MatchSimple.FullMatch
| None => MatchSimple.SameNameDifferentArguments | None => MatchSimple.SameNameDifferentArguments
} }
@ -228,43 +240,37 @@ module Matcher = {
module FnDefinition = { module FnDefinition = {
type t = 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 run = (t: t, args: array<expressionValue>) => {
let argValues = getArgValues(t, args) let argValues = FRType.matchWithExpressionValueArray(t.inputs, args)
switch argValues { switch argValues {
| Some(values) => t.run(values) | Some(values) => t.run(values)
| None => Error("Impossible") | None => Error("Incorrect Types")
} }
} }
}
module Function = { let make = (~name, ~inputs, ~run): fnDefinition => {
type definitionId = int
let make = (~name, ~definitions): function => {
name: name,
definitions: definitions,
}
let makeDefinition = (~name, ~inputs, ~run): fnDefinition => {
name: name, name: name,
inputs: inputs, inputs: inputs,
run: run, run: run,
} }
} }
module Function = {
let make = (~name, ~definitions): function => {
name: name,
definitions: definitions,
}
}
module Registry = { 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 matchAndRun = (r: registry, fnName: string, args: array<expressionValue>) => {
let matchToDef = m => Matcher.Registry.matchToDef(r, m) let matchToDef = m => Matcher.Registry.matchToDef(r, m)
let showNameMatchDefinitions = matches => { let showNameMatchDefinitions = matches => {

View File

@ -9,34 +9,37 @@ module Wrappers = {
} }
module Prepare = { module Prepare = {
let recordWithTwoArgsToValues = (inputs: array<value>): result<array<value>, string> => let recordWithTwoArgsToValues = (inputs: array<frValue>): result<array<frValue>, string> =>
switch inputs { switch inputs {
| [Record([(_, n1), (_, n2)])] => Ok([n1, n2]) | [FRValueRecord([(_, n1), (_, n2)])] => Ok([n1, n2])
| _ => Error(impossibleError) | _ => Error(impossibleError)
} }
let twoNumberInputs = (inputs: array<value>): result<(float, float), string> => { let twoNumberInputs = (inputs: array<frValue>): result<(float, float), string> => {
switch inputs { switch inputs {
| [Number(n1), Number(n2)] => Ok(n1, n2) | [FRValueNumber(n1), FRValueNumber(n2)] => Ok(n1, n2)
| _ => Error(impossibleError) | _ => Error(impossibleError)
} }
} }
let twoDistOrNumber = (values: array<value>): result<(distOrNumber, distOrNumber), string> => { let twoDistOrNumber = (values: array<frValue>): result<
(frValueDistOrNumber, frValueDistOrNumber),
string,
> => {
switch values { switch values {
| [DistOrNumber(a1), DistOrNumber(a2)] => Ok(a1, a2) | [FRValueDistOrNumber(a1), FRValueDistOrNumber(a2)] => Ok(a1, a2)
| _ => Error(impossibleError) | _ => Error(impossibleError)
} }
} }
let twoDistOrNumberFromRecord = (values: array<value>) => let twoDistOrNumberFromRecord = (values: array<frValue>) =>
values->recordWithTwoArgsToValues->E.R.bind(twoDistOrNumber) values->recordWithTwoArgsToValues->E.R.bind(twoDistOrNumber)
} }
module Process = { module Process = {
let twoDistsOrNumbersToDist = ( let twoDistsOrNumbersToDist = (
~fn: ((float, float)) => result<DistributionTypes.genericDist, string>, ~fn: ((float, float)) => result<DistributionTypes.genericDist, string>,
~values: (distOrNumber, distOrNumber), ~values: (frValueDistOrNumber, frValueDistOrNumber),
) => { ) => {
let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000) let toSampleSet = r => GenericDist.toSampleSetDist(r, 1000)
let sampleSetToExpressionValue = ( let sampleSetToExpressionValue = (
@ -65,10 +68,10 @@ module Process = {
} }
switch values { switch values {
| (Number(a1), Number(a2)) => fn((a1, a2))->E.R2.fmap(Wrappers.evDistribution) | (FRValueNumber(a1), FRValueNumber(a2)) => fn((a1, a2))->E.R2.fmap(Wrappers.evDistribution)
| (Dist(a1), Number(a2)) => singleVarSample(a1, r => fn((r, a2))) | (FRValueDist(a1), FRValueNumber(a2)) => singleVarSample(a1, r => fn((r, a2)))
| (Number(a1), Dist(a2)) => singleVarSample(a2, r => fn((a1, r))) | (FRValueNumber(a1), FRValueDist(a2)) => singleVarSample(a2, r => fn((a1, r)))
| (Dist(a1), Dist(a2)) => { | (FRValueDist(a1), FRValueDist(a2)) => {
let altFn = (a, b) => fn((a, b))->mapFnResult let altFn = (a, b) => fn((a, b))->mapFnResult
let sampleSetResult = let sampleSetResult =
E.R.merge(toSampleSet(a1), toSampleSet(a2)) E.R.merge(toSampleSet(a1), toSampleSet(a2))
@ -95,23 +98,23 @@ module TwoArgDist = {
r->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_)) r->E.R.bind(Process.twoDistsOrNumbersToDistUsingSymbolicDist(~fn, ~values=_))
let mkRegular = (name, fn) => { 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) inputs->Prepare.twoDistOrNumber->process(~fn)
) )
} }
let mkDef90th = (name, fn) => { let mkDef90th = (name, fn) => {
Function.makeDefinition( FnDefinition.make(
~name, ~name,
~inputs=[I_Record([("p5", I_DistOrNumber), ("p95", I_DistOrNumber)])], ~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])],
~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn), ~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn),
) )
} }
let mkDefMeanStdev = (name, fn) => { let mkDefMeanStdev = (name, fn) => {
Function.makeDefinition( FnDefinition.make(
~name, ~name,
~inputs=[I_Record([("mean", I_DistOrNumber), ("stdev", I_DistOrNumber)])], ~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])],
~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn), ~run=inputs => inputs->Prepare.twoDistOrNumberFromRecord->process(~fn),
) )
} }

View File

@ -52,7 +52,7 @@ let more = [
), ),
Function.make( Function.make(
~name="To", ~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 Some functions from modules `L`, `O`, and `R` below were copied directly from
running `rescript convert -all` on Rationale https://github.com/jonlaing/rationale running `rescript convert -all` on Rationale https://github.com/jonlaing/rationale
*/ */
let equals = (a,b) => a === b
module FloatFloatMap = { module FloatFloatMap = {
module Id = Belt.Id.MakeComparable({ module Id = Belt.Id.MakeComparable({
type t = float type t = float