squiggle/src/interface/Prop.re
2020-03-02 10:13:52 +00:00

329 lines
7.6 KiB
ReasonML

module Value = {
type conditional = {
name: string,
truthValue: bool,
};
type t =
| SelectSingle(string)
| DateTime(MomentRe.Moment.t)
| FloatPoint(float)
| Probability(float)
| DistPlusIngredients(DistTypes.distPlusIngredients)
| ConditionalArray(array(conditional))
| FloatCdf(string);
module ConditionalArray = {
let get = (conditionals: array(conditional), name: string) =>
Belt.Array.getBy(conditionals, (c: conditional) => c.name == name);
};
};
module ValueCombination = {
type pointsToEvenlySample = int;
type dateTimeRange = {
startTime: MomentRe.Moment.t,
endTime: MomentRe.Moment.t,
pointsWithin: int,
};
type floatPointRange = {
startTime: float,
endTime: float,
pointsWithin: int,
};
type range('a) = {
beginning: 'a,
ending: 'a,
pointsToEvenlySample,
};
type t =
| SelectSingle
| DateTime(range(MomentRe.Moment.t))
| FloatPoint(range(MomentRe.Moment.t))
| Probability(pointsToEvenlySample);
};
module ValueCluster = {
type conditional = {
name: string,
truthValue: bool,
};
type pointsToEvenlySample = int;
type dateTimeRange = {
startTime: MomentRe.Moment.t,
endTime: MomentRe.Moment.t,
pointsWithin: int,
};
type floatPointRange = {
startTime: float,
endTime: float,
pointsWithin: int,
};
type range('a) = {
beginning: 'a,
ending: 'a,
pointsToEvenlySample,
};
type t =
| SelectSingle([ | `combination | `item(string)])
| DateTime(
[
| `combination(range(MomentRe.Moment.t))
| `item(MomentRe.Moment.t)
],
)
| FloatPoint(
[ | `combination(range(MomentRe.Moment.t)) | `item(string)],
)
| Probability([ | `item(string)])
| DistPlusIngredients([ | `item(DistTypes.distPlusIngredients)])
| ConditionalArray([ | `item(array(conditional))])
| FloatCdf([ | `item(string)]);
};
module Type = {
type selectOption = {
id: string,
name: string,
};
type selectSingle = {
options: list(selectOption),
default: option(string),
};
type conditionals = {
defaults: array(Value.conditional),
options: array(string),
};
let makeConditionals = (defaults, options): conditionals => {
defaults,
options,
};
type floatPoint = {validatations: list(float => bool)};
type withDefaultMinMax('a) = {
default: option('a),
min: option('a),
max: option('a),
};
type withDefault('a) = {default: option('a)};
type t =
| SelectSingle(selectSingle)
| FloatPoint(withDefaultMinMax(float))
| Probability(withDefault(float))
| DateTime(withDefaultMinMax(MomentRe.Moment.t))
| Year(withDefaultMinMax(float))
| Conditionals(conditionals)
| FloatCdf;
let default = (t: t) =>
switch (t) {
| Conditionals(s) => Some(Value.ConditionalArray(s.defaults))
| Year(r) => r.default->Belt.Option.map(p => Value.FloatPoint(p))
| FloatPoint(r) => r.default->Belt.Option.map(p => Value.FloatPoint(p))
| Probability(r) => r.default->Belt.Option.map(p => Value.Probability(p))
| DateTime(r) => r.default->Belt.Option.map(p => Value.DateTime(p))
| SelectSingle(r) =>
r.default->Belt.Option.map(p => Value.SelectSingle(p))
| FloatCdf => None
};
};
module ValueMap = {
module MS = Belt.Map.String;
type t = MS.t(Value.t);
let get = (t: t, s) => MS.get(t, s);
let keys = MS.keysToArray;
let map = MS.map;
let fromArray = (r): t => MS.fromArray(r);
let values = (t: t) => t |> MS.valuesToArray;
let update = (t, k, v) => MS.update(t, k, _ => v);
let toArray = MS.toArray;
let fromOptionalMap = (t: MS.t(option(Value.t))): t =>
MS.keep(t, (_, d) => E.O.isSome(d))
->MS.map(d => E.O.toExn("This should not have happened", d));
let fromOptionalArray = (r): t => MS.fromArray(r) |> fromOptionalMap;
};
module ValueClusterMap = {
module MS = Belt.Map.String;
type t = MS.t(ValueCluster.t);
let get = (t: t, s) => MS.get(t, s);
let keys = MS.keysToArray;
let map = MS.map;
let fromArray = (r): t => MS.fromArray(r);
let values = (t: t) => t |> MS.valuesToArray;
let update = (t, k, v) => MS.update(t, k, _ => v);
let toArray = MS.toArray;
let fromOptionalMap = (t: MS.t(option(ValueCluster.t))): t =>
MS.keep(t, (_, d) => E.O.isSome(d))
->MS.map(d => E.O.toExn("This should not have happened", d));
let fromOptionalArray = (r): t => MS.fromArray(r) |> fromOptionalMap;
};
module TypeWithMetadata = {
// TODO: Figure out a better name for assumptionType
type assumptionType =
| PRIMARY_INPUT
| ASSUMPTION;
type t = {
id: string,
name: string,
description: option(string),
type_: Type.t,
assumptionType,
};
type ts = array(t);
let make =
(
~name,
~type_,
~id=name,
~description=None,
~assumptionType=PRIMARY_INPUT,
(),
) => {
id,
name,
type_,
description,
assumptionType,
};
let currentYear =
make(
~id="currentYear",
~name="Current Day",
~description=None,
~type_=
DateTime({
default: Some(MomentRe.momentNow()),
min: Some(MomentRe.momentNow()),
max: Some(MomentRe.momentNow()),
}),
~assumptionType=ASSUMPTION,
(),
);
let age =
make(
~id="age",
~name="Current Age",
~description=None,
~type_=
FloatPoint({
default: Some(40.0),
min: Some(0.0),
max: Some(100.0),
}),
~assumptionType=PRIMARY_INPUT,
(),
);
let sex =
make(
~id="sex",
~name="Sex",
~description=None,
~type_=
SelectSingle({
options: [
{id: "male", name: "Male"},
{id: "female", name: "Female"},
],
default: Some("female"),
}),
~assumptionType=PRIMARY_INPUT,
(),
);
};
module Model = {
type t = {
name: string,
id: string,
fileName: string,
description: string,
author: string,
version: string,
inputTypes: array(TypeWithMetadata.t),
outputTypes: array(TypeWithMetadata.t),
run: array(option(Value.t)) => option(Value.t),
}
and combo = {
model: t,
inputValues: ValueMap.t,
outputValues: ValueMap.t,
};
module InputTypes = {
let keys = (t: t) =>
t.inputTypes |> E.A.fmap((r: TypeWithMetadata.t) => r.id);
let getBy = (t: t, fn) => t.inputTypes |> E.A.getBy(_, fn);
};
};
module Combo = {
type t = Model.combo;
type valueArray = array(option(Value.t));
module InputValues = {
let defaults = (t: Model.t) =>
t.inputTypes
|> E.A.fmap((o: TypeWithMetadata.t) => (o.id, Type.default(o.type_)))
|> ValueMap.fromOptionalArray;
let isValid = (t: t) =>
t.model
|> Model.InputTypes.keys
|> E.A.fmap(ValueMap.get(t.inputValues))
|> Belt.Array.some(_, E.O.isNone);
let update = (t: t, key: string, onUpdate: option(Value.t)) =>
ValueMap.update(t.inputValues, key, onUpdate);
let toValueArray = (t: t): valueArray => {
t.model.inputTypes
|> E.A.fmap((r: TypeWithMetadata.t) =>
t.inputValues->ValueMap.get(r.id)
);
};
};
let updateInputValue = (t: t, k, u) => {
...t,
inputValues: InputValues.update(t, k, u),
};
let inputTypeValuePairs = (t: t) =>
t.model.inputTypes
|> E.A.fmap((i: TypeWithMetadata.t) =>
(i, ValueMap.get(t.inputValues, i.id))
);
let fromModel = (t: Model.t): t => {
model: t,
inputValues: InputValues.defaults(t),
outputValues: InputValues.defaults(t),
};
let run = (t: t, f): ValueMap.t => f(t.inputValues);
};