Cleanup part 1
This commit is contained in:
		
							parent
							
								
									1421c6a9b1
								
							
						
					
					
						commit
						255c1763e5
					
				| 
						 | 
				
			
			@ -1 +1 @@
 | 
			
		|||
let entries = EntryTypes.[ExpressionTreeExamples.entry];
 | 
			
		||||
let entries = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -1,88 +0,0 @@
 | 
			
		|||
// Examples:
 | 
			
		||||
// mm(floor(uniform(30,35)), normal(50,20), [.25,.5])
 | 
			
		||||
// mm(floor(normal(28,4)), normal(32,2), uniform(20,24), [.5,.2,.1])
 | 
			
		||||
// mm(5 to 20, floor(normal(20,2)), [.5, .5])"
 | 
			
		||||
// floor(3 to 4)
 | 
			
		||||
// uniform(0,1) > 0.3 ? lognormal(6.652, -0.41): 0
 | 
			
		||||
 | 
			
		||||
// let timeDist ={
 | 
			
		||||
//   let ingredients = DistPlusRenderer.Inputs.Ingredients.make(
 | 
			
		||||
//     ~guesstimatorString="(floor(10 to 15))",
 | 
			
		||||
//     ~domain=RightLimited({xPoint: 50.0, excludingProbabilityMass: 0.3}),
 | 
			
		||||
//     ~unit=
 | 
			
		||||
//       DistTypes.TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
 | 
			
		||||
//     ());
 | 
			
		||||
//   let inputs = DistPlusRenderer.Inputs.make(~distPlusIngredients=ingredients,())
 | 
			
		||||
//   inputs |> DistPlusRenderer.run
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// let setup = dist =>
 | 
			
		||||
//   DistPlusRenderer.Inputs.make(~distPlusIngredients=dist,())
 | 
			
		||||
//   |> DistPlusRenderer.run
 | 
			
		||||
//   |> E.R.fmap(distPlus => <DistPlusPlot distPlus />)
 | 
			
		||||
//   |> E.R.toOption
 | 
			
		||||
//   |> E.O.toExn("")
 | 
			
		||||
 | 
			
		||||
// let simpleExample = (name, guesstimatorString) =>
 | 
			
		||||
//   <>
 | 
			
		||||
//     <h3 className="text-gray-600 text-lg font-bold">
 | 
			
		||||
//       {name |> ReasonReact.string}
 | 
			
		||||
//     </h3>
 | 
			
		||||
//     {setup(DistPlusRenderer.Inputs.Ingredients.make(~guesstimatorString, ()))}
 | 
			
		||||
//   </>;
 | 
			
		||||
 | 
			
		||||
// let timeExample = (name, guesstimatorString) =>
 | 
			
		||||
//   <>
 | 
			
		||||
//     <h3 className="text-gray-600 text-lg font-bold">
 | 
			
		||||
//       {name |> ReasonReact.string}
 | 
			
		||||
//     </h3>
 | 
			
		||||
//     {setup(
 | 
			
		||||
//        DistPlusRenderer.Inputs.Ingredients.make(
 | 
			
		||||
//          ~guesstimatorString,
 | 
			
		||||
//          ~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
 | 
			
		||||
//          (),
 | 
			
		||||
//        ),
 | 
			
		||||
//      )}
 | 
			
		||||
//   </>;
 | 
			
		||||
 | 
			
		||||
// let distributions = () =>
 | 
			
		||||
//   <div>
 | 
			
		||||
//     <div>
 | 
			
		||||
//       <h2 className="text-gray-800 text-xl font-bold">
 | 
			
		||||
//         {"Initial Section" |> ReasonReact.string}
 | 
			
		||||
//       </h2>
 | 
			
		||||
//         {simpleExample("Continuous", "5 to 20")}
 | 
			
		||||
//         {simpleExample("Continuous, wide range", "1 to 1000000")}
 | 
			
		||||
//         {simpleExample("Continuous, tiny values", "0.000000001 to 0.00000001")}
 | 
			
		||||
//         {simpleExample(
 | 
			
		||||
//            "Continuous large values",
 | 
			
		||||
//            "50000000000000 to 200000000000000000",
 | 
			
		||||
//          )}
 | 
			
		||||
//         {simpleExample("Discrete", "floor(10 to 20)")}
 | 
			
		||||
//         {simpleExample(
 | 
			
		||||
//            "Discrete and below 0, normal(10,30)",
 | 
			
		||||
//            "floor(normal(10,30))",
 | 
			
		||||
//          )}
 | 
			
		||||
//         {simpleExample("Discrete, wide range", "floor(10 to 200000)")}
 | 
			
		||||
//         {simpleExample("Mixed", "mm(5 to 20, floor(20 to 30), [.5,.5])")}
 | 
			
		||||
//         {simpleExample("Mixed, Early-Discrete Point", "mm(1, 5 to 20, [.5,.5])")}
 | 
			
		||||
//         {simpleExample(
 | 
			
		||||
//            "Mixed, Two-Discrete Points",
 | 
			
		||||
//            "mm(0,10, 5 to 20, [.5,.5,.5])",
 | 
			
		||||
//          )}
 | 
			
		||||
//         <h2 className="text-gray-800 text-xl font-bold">
 | 
			
		||||
//           {"Over Time" |> ReasonReact.string}
 | 
			
		||||
//         </h2>
 | 
			
		||||
//         {timeExample("Continuous", "5 to 20")}
 | 
			
		||||
//         {timeExample("Continuous Over Long Period", "500 to 200000")}
 | 
			
		||||
//         {timeExample("Continuous Over Short Period", "0.0001 to 0.001")}
 | 
			
		||||
//         {timeExample(
 | 
			
		||||
//            "Continuous Over Very Long Period",
 | 
			
		||||
//            "500 to 20000000000000",
 | 
			
		||||
//          )}
 | 
			
		||||
//         {timeExample("Discrete", "floor(5 to 20)")}
 | 
			
		||||
//         {timeExample("Mixed", "mm(5 to 20, floor(5 to 20), [.5,.5])")}
 | 
			
		||||
//     </div>
 | 
			
		||||
//   </div>;
 | 
			
		||||
 | 
			
		||||
// let entry = EntryTypes.(entry(~title="Mixed Distributions", ~render=distributions));
 | 
			
		||||
| 
						 | 
				
			
			@ -1,72 +0,0 @@
 | 
			
		|||
// let setup = dist =>
 | 
			
		||||
//   DistPlusRenderer.Inputs.make(~distPlusIngredients=dist, ())
 | 
			
		||||
//   |> DistPlusRenderer.run
 | 
			
		||||
//   |> E.R.fmap(distPlus => <DistPlusPlot distPlus />)
 | 
			
		||||
//   |> E.R.toOption
 | 
			
		||||
//   |> E.O.toExn("")
 | 
			
		||||
 | 
			
		||||
// let simpleExample = (guesstimatorString, ~problem="", ()) =>
 | 
			
		||||
//   <>
 | 
			
		||||
//     <p> {guesstimatorString |> ReasonReact.string} </p>
 | 
			
		||||
//     <p> {problem |> (e => "problem: " ++ e) |> ReasonReact.string} </p>
 | 
			
		||||
//     {setup(
 | 
			
		||||
//        DistPlusRenderer.Inputs.Ingredients.make(~guesstimatorString, ()),
 | 
			
		||||
//      )}
 | 
			
		||||
//   </>;
 | 
			
		||||
 | 
			
		||||
let distributions = () =>
 | 
			
		||||
  <div>
 | 
			
		||||
    <div>
 | 
			
		||||
      <h2 className="text-gray-800 text-xl font-bold">
 | 
			
		||||
        {"Initial Section" |> ReasonReact.string}
 | 
			
		||||
      </h2>
 | 
			
		||||
      // {simpleExample(
 | 
			
		||||
      //    "normal(-1, 1) + normal(5, 2)",
 | 
			
		||||
      //    ~problem="Tails look too flat",
 | 
			
		||||
      //    (),
 | 
			
		||||
      //  )}
 | 
			
		||||
      // {simpleExample(
 | 
			
		||||
      //    "mm(normal(4,2), normal(10,1))",
 | 
			
		||||
      //    ~problem="Tails look too flat",
 | 
			
		||||
      //    (),
 | 
			
		||||
      //  )}
 | 
			
		||||
      // {simpleExample(
 | 
			
		||||
      //    "normal(-1, 1) * normal(5, 2)",
 | 
			
		||||
      //    ~problem="This looks really weird",
 | 
			
		||||
      //    (),
 | 
			
		||||
      //  )}
 | 
			
		||||
      // {simpleExample(
 | 
			
		||||
      //    "normal(1,2) * normal(2,2) * normal(3,1)",
 | 
			
		||||
      //    ~problem="Seems like important parts are cut off",
 | 
			
		||||
      //    (),
 | 
			
		||||
      //  )}
 | 
			
		||||
      // {simpleExample(
 | 
			
		||||
      //    "mm(uniform(0, 1) , normal(3,2))",
 | 
			
		||||
      //    ~problem="Uniform distribution seems to break multimodal",
 | 
			
		||||
      //    (),
 | 
			
		||||
      //  )}
 | 
			
		||||
      // {simpleExample(
 | 
			
		||||
      //   "truncate(mm(1 to 10, 10 to 30), 10, 20)",
 | 
			
		||||
      //    ~problem="Truncate seems to have no effect",
 | 
			
		||||
      //    (),
 | 
			
		||||
      //  )}
 | 
			
		||||
      // {simpleExample(
 | 
			
		||||
      //   "normal(5,2)*(10^3)",
 | 
			
		||||
      //    ~problem="Multiplied items should be evaluated.",
 | 
			
		||||
      //    (),
 | 
			
		||||
      //  )}
 | 
			
		||||
      // {simpleExample(
 | 
			
		||||
      //   "normal(5,10*3)",
 | 
			
		||||
      //    ~problem="At least simple operations in the distributions should be evaluated.",
 | 
			
		||||
      //    (),
 | 
			
		||||
      //  )}
 | 
			
		||||
      // {simpleExample(
 | 
			
		||||
      //   "normal(5,10)^3",
 | 
			
		||||
      //    ~problem="Exponentiation not yet supported",
 | 
			
		||||
      //    (),
 | 
			
		||||
      //  )}
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>;
 | 
			
		||||
 | 
			
		||||
let entry =
 | 
			
		||||
  EntryTypes.(entry(~title="ExpressionTree", ~render=distributions));
 | 
			
		||||
							
								
								
									
										20
									
								
								src/App.re
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/App.re
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,26 +1,15 @@
 | 
			
		|||
type route =
 | 
			
		||||
  | Model(string)
 | 
			
		||||
  | DistBuilder
 | 
			
		||||
  | Home
 | 
			
		||||
  | NotFound;
 | 
			
		||||
 | 
			
		||||
let routeToPath = route =>
 | 
			
		||||
  switch (route) {
 | 
			
		||||
  | Model(modelId) => "/m/" ++ modelId
 | 
			
		||||
  | DistBuilder => "/dist-builder"
 | 
			
		||||
  | Home => "/"
 | 
			
		||||
  | _ => "/"
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
module Models = {
 | 
			
		||||
  let all = [|
 | 
			
		||||
    EAFunds.Interface.model,
 | 
			
		||||
    GlobalCatastrophe.Interface.model,
 | 
			
		||||
    Human.Interface.model,
 | 
			
		||||
  |];
 | 
			
		||||
  let getById = id => E.A.getBy(all, r => r.id == id);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module Menu = {
 | 
			
		||||
  module Styles = {
 | 
			
		||||
    open Css;
 | 
			
		||||
| 
						 | 
				
			
			@ -82,7 +71,6 @@ let make = () => {
 | 
			
		|||
 | 
			
		||||
  let routing =
 | 
			
		||||
    switch (url.path) {
 | 
			
		||||
    | ["m", modelId] => Model(modelId)
 | 
			
		||||
    | ["dist-builder"] => DistBuilder
 | 
			
		||||
    | [] => Home
 | 
			
		||||
    | _ => NotFound
 | 
			
		||||
| 
						 | 
				
			
			@ -91,14 +79,6 @@ let make = () => {
 | 
			
		|||
  <>
 | 
			
		||||
    <Menu />
 | 
			
		||||
    {switch (routing) {
 | 
			
		||||
     | Model(id) =>
 | 
			
		||||
       (
 | 
			
		||||
         switch (Models.getById(id)) {
 | 
			
		||||
         | Some(model) => <FormBuilder.ModelForm model key=id />
 | 
			
		||||
         | None => <div> {"Page is not found" |> R.ste} </div>
 | 
			
		||||
         }
 | 
			
		||||
       )
 | 
			
		||||
       |> fixedLength
 | 
			
		||||
     | DistBuilder => <DistBuilder />
 | 
			
		||||
     | Home => <Home />
 | 
			
		||||
     | _ => fixedLength({"Page is not found" |> R.ste})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,6 @@ export class CodeEditor extends React.Component {
 | 
			
		|||
        mode="golang"
 | 
			
		||||
        height="400px"
 | 
			
		||||
        width="100%"
 | 
			
		||||
        keyboardHandler="vim"
 | 
			
		||||
        theme="github"
 | 
			
		||||
        showGutter={false}
 | 
			
		||||
        highlightActiveLine={false}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
 | 
			
		||||
<head>
 | 
			
		||||
  <meta charset="UTF-8">
 | 
			
		||||
  <title>Highly Speculative Forecasts</title>
 | 
			
		||||
  <title>Squiggle Language</title>
 | 
			
		||||
  <link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,900" rel="stylesheet">
 | 
			
		||||
  <link href="./styles/index.css" rel="stylesheet">
 | 
			
		||||
  <script src="./Index.re" defer></script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,104 +0,0 @@
 | 
			
		|||
open Prop;
 | 
			
		||||
 | 
			
		||||
type formState = {
 | 
			
		||||
  combo: Combo.t,
 | 
			
		||||
  setCombo: (Combo.t => Combo.t) => unit,
 | 
			
		||||
  setInputValue: (Combo.t, string, option(Value.t)) => unit,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let makeHelpers = (combo): formState => {
 | 
			
		||||
  let (combo, setCombo) = React.useState(() => combo);
 | 
			
		||||
  let setInputValue = (combo, id, newValue) =>
 | 
			
		||||
    setCombo(_ => Combo.updateInputValue(combo, id, newValue));
 | 
			
		||||
  {combo, setCombo, setInputValue};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let propValue = (t: Prop.Value.t) => {
 | 
			
		||||
  switch (t) {
 | 
			
		||||
  | SelectSingle(r) => r |> ReasonReact.string
 | 
			
		||||
  | ConditionalArray(r) => "Array" |> ReasonReact.string
 | 
			
		||||
  | DistPlusIngredients((r: DistPlusRenderer.Inputs.ingredients)) =>
 | 
			
		||||
    let newDistribution =
 | 
			
		||||
      DistPlusRenderer.Inputs.make(
 | 
			
		||||
        ~distPlusIngredients=r,
 | 
			
		||||
        (),
 | 
			
		||||
      )
 | 
			
		||||
      |> DistPlusRenderer.run;
 | 
			
		||||
    switch (newDistribution) {
 | 
			
		||||
    | Ok(distribution) => <div> <DistPlusPlot distPlus=distribution /> </div>
 | 
			
		||||
    // <input
 | 
			
		||||
    //   readOnly=true
 | 
			
		||||
    //   className="shadow appearance-none border w-1/3 rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
 | 
			
		||||
    //   value={r.guesstimatorString}
 | 
			
		||||
    // />
 | 
			
		||||
    // <select
 | 
			
		||||
    //   defaultValue="years"
 | 
			
		||||
    //   readOnly=true
 | 
			
		||||
    //   className="appearance-none w-32 bg-white border border-gray-400 hover:border-gray-500 px-4 py-2 pr-8 rounded shadow leading-tight focus:outline-none focus:shadow-outline">
 | 
			
		||||
    //   <option> {"years" |> ReasonReact.string} </option>
 | 
			
		||||
    // </select>
 | 
			
		||||
    // <div
 | 
			
		||||
    //   className="w-1/3 border w-1/2 rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline bg-white">
 | 
			
		||||
    //   {"30 to infinity, 80% mass" |> ReasonReact.string}
 | 
			
		||||
    // </div>
 | 
			
		||||
    | Error(e) => e |> ReasonReact.string
 | 
			
		||||
    };
 | 
			
		||||
  | FloatCdf(_) => <div />
 | 
			
		||||
  | Probability(r) =>
 | 
			
		||||
    (r *. 100. |> Js.Float.toFixed) ++ "%" |> ReasonReact.string
 | 
			
		||||
  | DateTime(r) => r |> MomentRe.Moment.defaultFormat |> ReasonReact.string
 | 
			
		||||
  | FloatPoint(r) => r |> Js.Float.toFixed |> ReasonReact.string
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module ModelForm = {
 | 
			
		||||
  let handleChange = (handleChange, event) =>
 | 
			
		||||
    handleChange(ReactEvent.Form.target(event)##value);
 | 
			
		||||
 | 
			
		||||
  [@react.component]
 | 
			
		||||
  let make = (~model: Model.t) => {
 | 
			
		||||
    let formState = makeHelpers(Combo.fromModel(model));
 | 
			
		||||
    <div>
 | 
			
		||||
      <div
 | 
			
		||||
        className="bg-white rounded px-8 pt-6 pb-8 mb-4 mt-6 border-gray-200 border-solid border-2">
 | 
			
		||||
        <h1 className="text-gray-800 text-xl font-bold">
 | 
			
		||||
          {model.name |> ReasonReact.string}
 | 
			
		||||
        </h1>
 | 
			
		||||
        <p> {model.description |> ReasonReact.string} </p>
 | 
			
		||||
        <p> {model.author |> ReasonReact.string} </p>
 | 
			
		||||
        <ForetoldComponents.Link
 | 
			
		||||
          href={
 | 
			
		||||
            "https://github.com/foretold-app/estiband/blob/master/src/models/"
 | 
			
		||||
            ++ model.fileName
 | 
			
		||||
          }>
 | 
			
		||||
          {"Model Code" |> ReasonReact.string}
 | 
			
		||||
        </ForetoldComponents.Link>
 | 
			
		||||
        {Combo.inputTypeValuePairs(formState.combo)
 | 
			
		||||
         |> E.A.fmap(((type_: TypeWithMetadata.t, value)) =>
 | 
			
		||||
              <div className="box-border">
 | 
			
		||||
                <label
 | 
			
		||||
                  className="block text-gray-700 text-sm font-bold mb-2 w-32 mt-3">
 | 
			
		||||
                  {type_.name |> ReasonReact.string}
 | 
			
		||||
                </label>
 | 
			
		||||
                <ValueForm
 | 
			
		||||
                  type_
 | 
			
		||||
                  value
 | 
			
		||||
                  onChange={newValue =>
 | 
			
		||||
                    formState.setInputValue(
 | 
			
		||||
                      formState.combo,
 | 
			
		||||
                      type_.id,
 | 
			
		||||
                      newValue,
 | 
			
		||||
                    )
 | 
			
		||||
                  }
 | 
			
		||||
                />
 | 
			
		||||
              </div>
 | 
			
		||||
            )
 | 
			
		||||
         |> ReasonReact.array}
 | 
			
		||||
        <div className="bg-green-100 p-2 rounded-sm mt-6 text-lg">
 | 
			
		||||
          {model.run(Prop.Combo.InputValues.toValueArray(formState.combo))
 | 
			
		||||
           |> R.O.fmapOrNull(propValue)}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>;
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,329 +0,0 @@
 | 
			
		|||
module Value = {
 | 
			
		||||
  type conditional = {
 | 
			
		||||
    name: string,
 | 
			
		||||
    truthValue: bool,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  type t =
 | 
			
		||||
    | SelectSingle(string)
 | 
			
		||||
    | DateTime(MomentRe.Moment.t)
 | 
			
		||||
    | FloatPoint(float)
 | 
			
		||||
    | Probability(float)
 | 
			
		||||
    | DistPlusIngredients(DistPlusRenderer.Inputs.ingredients)
 | 
			
		||||
    | 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(DistPlusRenderer.Inputs.ingredients)])
 | 
			
		||||
    | 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);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,157 +0,0 @@
 | 
			
		|||
open Prop;
 | 
			
		||||
let handleChange = (handleChange, event) =>
 | 
			
		||||
  handleChange(ReactEvent.Form.target(event)##value);
 | 
			
		||||
type onChange = option(Value.t) => unit;
 | 
			
		||||
 | 
			
		||||
module ConditionalReducer = {
 | 
			
		||||
  type action =
 | 
			
		||||
    | ADD_OR_UPDATE_CONDITIONAL(Value.conditional)
 | 
			
		||||
    | REMOVE_CONDITIONAL(Value.conditional);
 | 
			
		||||
 | 
			
		||||
  let reducer = (items: array(Value.conditional), action: action) =>
 | 
			
		||||
    switch (action) {
 | 
			
		||||
    | ADD_OR_UPDATE_CONDITIONAL(conditional) =>
 | 
			
		||||
      items->E.A.hasBy(c => c.name == conditional.name)
 | 
			
		||||
        ? items
 | 
			
		||||
          |> E.A.fmap((r: Value.conditional) =>
 | 
			
		||||
               r.name == conditional.name ? conditional : r
 | 
			
		||||
             )
 | 
			
		||||
        : E.A.append(items, [|conditional|])
 | 
			
		||||
    | REMOVE_CONDITIONAL(conditional) =>
 | 
			
		||||
      items
 | 
			
		||||
      |> E.A.filter((c: Value.conditional) => c.name != conditional.name)
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
[@react.component]
 | 
			
		||||
let make =
 | 
			
		||||
    (
 | 
			
		||||
      ~type_: TypeWithMetadata.t,
 | 
			
		||||
      ~value: option(Value.t),
 | 
			
		||||
      ~onChange: onChange,
 | 
			
		||||
    ) => {
 | 
			
		||||
  switch (type_.type_, value) {
 | 
			
		||||
  | (Conditionals(l), Some(ConditionalArray(n))) =>
 | 
			
		||||
    <div>
 | 
			
		||||
      {n
 | 
			
		||||
       |> E.A.fmap((r: Value.conditional) =>
 | 
			
		||||
            <div
 | 
			
		||||
              onClick={_ =>
 | 
			
		||||
                onChange(
 | 
			
		||||
                  Some(
 | 
			
		||||
                    Value.ConditionalArray(
 | 
			
		||||
                      ConditionalReducer.reducer(
 | 
			
		||||
                        n,
 | 
			
		||||
                        REMOVE_CONDITIONAL({name: r.name, truthValue: true}),
 | 
			
		||||
                      ),
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
                )
 | 
			
		||||
              }>
 | 
			
		||||
              {r.name |> ReasonReact.string}
 | 
			
		||||
              {(r.truthValue ? " = True" : " = False") |> ReasonReact.string}
 | 
			
		||||
            </div>
 | 
			
		||||
          )
 | 
			
		||||
       |> ReasonReact.array}
 | 
			
		||||
      {l.options
 | 
			
		||||
       |> E.A.fmap(r =>
 | 
			
		||||
            <div
 | 
			
		||||
              className="max-w-sm rounded overflow-hidden shadow-sm py-1 px-2 rounded mb-3 bg-gray-200">
 | 
			
		||||
              {r |> ReasonReact.string}
 | 
			
		||||
              <button
 | 
			
		||||
                className="bg-blue-500 hover:bg-blue-700 text-white py-0 px-1 rounded"
 | 
			
		||||
                onClick={e => {
 | 
			
		||||
                  ReactEvent.Synthetic.preventDefault(e);
 | 
			
		||||
                  onChange(
 | 
			
		||||
                    Some(
 | 
			
		||||
                      Value.ConditionalArray(
 | 
			
		||||
                        ConditionalReducer.reducer(
 | 
			
		||||
                          n,
 | 
			
		||||
                          ADD_OR_UPDATE_CONDITIONAL({
 | 
			
		||||
                            name: r,
 | 
			
		||||
                            truthValue: true,
 | 
			
		||||
                          }),
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                    ),
 | 
			
		||||
                  );
 | 
			
		||||
                  ();
 | 
			
		||||
                }}>
 | 
			
		||||
                {"=True" |> ReasonReact.string}
 | 
			
		||||
              </button>
 | 
			
		||||
              <button
 | 
			
		||||
                className="hover:bg-red-700 text-white py-0 px-1 rounded bg-red-500"
 | 
			
		||||
                onClick={e => {
 | 
			
		||||
                  ReactEvent.Synthetic.preventDefault(e);
 | 
			
		||||
                  onChange(
 | 
			
		||||
                    Some(
 | 
			
		||||
                      Value.ConditionalArray(
 | 
			
		||||
                        ConditionalReducer.reducer(
 | 
			
		||||
                          n,
 | 
			
		||||
                          ADD_OR_UPDATE_CONDITIONAL({
 | 
			
		||||
                            name: r,
 | 
			
		||||
                            truthValue: false,
 | 
			
		||||
                          }),
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                    ),
 | 
			
		||||
                  );
 | 
			
		||||
                }}>
 | 
			
		||||
                {"=False" |> ReasonReact.string}
 | 
			
		||||
              </button>
 | 
			
		||||
            </div>
 | 
			
		||||
          )
 | 
			
		||||
       |> ReasonReact.array}
 | 
			
		||||
    </div>
 | 
			
		||||
  | (Conditionals(l), _) =>
 | 
			
		||||
    l.options |> E.A.fmap(r => r |> ReasonReact.string) |> ReasonReact.array
 | 
			
		||||
  | (Year(_), Some(FloatPoint(r))) =>
 | 
			
		||||
    <input
 | 
			
		||||
      className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
 | 
			
		||||
      type_="number"
 | 
			
		||||
      value={r |> Js.Float.toString}
 | 
			
		||||
      onChange={handleChange(r =>
 | 
			
		||||
        switch (Js.Float.fromString(r)) {
 | 
			
		||||
        | r => onChange(Some(Value.FloatPoint(r)))
 | 
			
		||||
        }
 | 
			
		||||
      )}
 | 
			
		||||
    />
 | 
			
		||||
  | (FloatPoint(_), Some(FloatPoint(r))) =>
 | 
			
		||||
    <input
 | 
			
		||||
      className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
 | 
			
		||||
      type_="number"
 | 
			
		||||
      value={r |> Js.Float.toString}
 | 
			
		||||
      onChange={handleChange(r =>
 | 
			
		||||
        switch (Js.Float.fromString(r)) {
 | 
			
		||||
        | r => onChange(Some(Value.FloatPoint(r)))
 | 
			
		||||
        }
 | 
			
		||||
      )}
 | 
			
		||||
    />
 | 
			
		||||
  | (Year(_), _)
 | 
			
		||||
  | (FloatPoint(_), _) => <input type_="number" value="" />
 | 
			
		||||
  | (SelectSingle(t), Some(SelectSingle(r))) =>
 | 
			
		||||
    <select
 | 
			
		||||
      defaultValue=r
 | 
			
		||||
      className="block appearance-none w-full bg-white border border-gray-400 hover:border-gray-500 px-4 py-2 pr-8 rounded shadow leading-tight focus:outline-none focus:shadow-outline"
 | 
			
		||||
      onChange={handleChange(l => onChange(Some(Value.SelectSingle(l))))}>
 | 
			
		||||
      {t.options
 | 
			
		||||
       |> E.A.of_list
 | 
			
		||||
       |> E.A.fmap((l: Type.selectOption) =>
 | 
			
		||||
            <option value={l.id} key={l.id}>
 | 
			
		||||
              {l.name |> ReasonReact.string}
 | 
			
		||||
            </option>
 | 
			
		||||
          )
 | 
			
		||||
       |> ReasonReact.array}
 | 
			
		||||
    </select>
 | 
			
		||||
  | (DateTime(_), Some(DateTime((d: MomentRe.Moment.t)))) =>
 | 
			
		||||
    <input
 | 
			
		||||
      type_="date"
 | 
			
		||||
      value={MomentRe.Moment.format("YYYY-MM-DD", d)}
 | 
			
		||||
      onChange={handleChange(r =>
 | 
			
		||||
        onChange(
 | 
			
		||||
          Some(Value.DateTime(MomentRe.momentWithFormat(r, "YYYY-MM-DD"))),
 | 
			
		||||
        )
 | 
			
		||||
      )}
 | 
			
		||||
    />
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,306 +0,0 @@
 | 
			
		|||
module Data = {
 | 
			
		||||
  type fund =
 | 
			
		||||
    | ANIMAL_WELFARE
 | 
			
		||||
    | GLOBAL_HEALTH
 | 
			
		||||
    | LONG_TERM_FUTURE
 | 
			
		||||
    | META;
 | 
			
		||||
 | 
			
		||||
  type group =
 | 
			
		||||
    | Fund(fund)
 | 
			
		||||
    | All;
 | 
			
		||||
 | 
			
		||||
  type output =
 | 
			
		||||
    | DONATIONS
 | 
			
		||||
    | CHANCE_OF_EXISTENCE
 | 
			
		||||
    | PAYOUTS;
 | 
			
		||||
 | 
			
		||||
  type conditionals =
 | 
			
		||||
    | WORLD_CATASTROPHE;
 | 
			
		||||
 | 
			
		||||
  type fundWithInfo = {
 | 
			
		||||
    group,
 | 
			
		||||
    name: string,
 | 
			
		||||
    existingDonations: option(float),
 | 
			
		||||
    existingPayouts: option(float),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let makeFundWithInfo = (name, group, existingDonations, existingPayouts) => {
 | 
			
		||||
    group,
 | 
			
		||||
    name,
 | 
			
		||||
    existingDonations,
 | 
			
		||||
    existingPayouts,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let funds = [|
 | 
			
		||||
    makeFundWithInfo(
 | 
			
		||||
      "Animal Welfare Fund",
 | 
			
		||||
      Fund(ANIMAL_WELFARE),
 | 
			
		||||
      Some(400000.0),
 | 
			
		||||
      Some(100000.0),
 | 
			
		||||
    ),
 | 
			
		||||
    makeFundWithInfo(
 | 
			
		||||
      "Global Health Fund",
 | 
			
		||||
      Fund(GLOBAL_HEALTH),
 | 
			
		||||
      Some(400000.0),
 | 
			
		||||
      Some(100000.0),
 | 
			
		||||
    ),
 | 
			
		||||
    makeFundWithInfo(
 | 
			
		||||
      "Long Term Future Fund",
 | 
			
		||||
      Fund(LONG_TERM_FUTURE),
 | 
			
		||||
      Some(400000.0),
 | 
			
		||||
      Some(100000.0),
 | 
			
		||||
    ),
 | 
			
		||||
    makeFundWithInfo(
 | 
			
		||||
      "Meta Fund",
 | 
			
		||||
      Fund(ANIMAL_WELFARE),
 | 
			
		||||
      Some(400000.0),
 | 
			
		||||
      Some(100000.0),
 | 
			
		||||
    ),
 | 
			
		||||
    makeFundWithInfo("All", All, None, None),
 | 
			
		||||
  |];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module Model = {
 | 
			
		||||
  open Data;
 | 
			
		||||
  let currentYear = 2020.;
 | 
			
		||||
  let firstYearStdDev = 400000.;
 | 
			
		||||
  type yearlyNumericDiff = {
 | 
			
		||||
    meanDiff: float,
 | 
			
		||||
    stdDiff: float,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let yearlyMeanGrowthRateIfNotClosed = (group: group): yearlyNumericDiff => {
 | 
			
		||||
    {meanDiff: 1.1, stdDiff: 1.2};
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let calculateDifference =
 | 
			
		||||
      (currentValue, dateTime, currentDateTime, y: yearlyNumericDiff) => {
 | 
			
		||||
    let yearDiff = MomentRe.diff(dateTime, currentDateTime, `days) /. 365.;
 | 
			
		||||
    let meanDiff = Js.Math.pow_float(~base=y.meanDiff, ~exp=yearDiff);
 | 
			
		||||
    let stdDevDiff = Js.Math.pow_float(~base=y.stdDiff, ~exp=yearDiff);
 | 
			
		||||
    GuesstimatorDist.logNormal(
 | 
			
		||||
      currentValue *. meanDiff,
 | 
			
		||||
      firstYearStdDev *. stdDevDiff,
 | 
			
		||||
    );
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let rec currentValue = (group: group, output) => {
 | 
			
		||||
    let sum = (): float =>
 | 
			
		||||
      currentValue(Fund(ANIMAL_WELFARE), output)
 | 
			
		||||
      +. currentValue(Fund(GLOBAL_HEALTH), output)
 | 
			
		||||
      +. currentValue(Fund(LONG_TERM_FUTURE), output)
 | 
			
		||||
      +. currentValue(Fund(META), output);
 | 
			
		||||
    switch (group, output) {
 | 
			
		||||
    | (Fund(ANIMAL_WELFARE), DONATIONS) => 300000.0
 | 
			
		||||
    | (Fund(ANIMAL_WELFARE), PAYOUTS) => 2300000.0
 | 
			
		||||
    | (Fund(GLOBAL_HEALTH), DONATIONS) => 1000000.0
 | 
			
		||||
    | (Fund(GLOBAL_HEALTH), PAYOUTS) => 500000.0
 | 
			
		||||
    | (Fund(LONG_TERM_FUTURE), DONATIONS) => 600000.0
 | 
			
		||||
    | (Fund(LONG_TERM_FUTURE), PAYOUTS) => 120000.0
 | 
			
		||||
    | (Fund(META), DONATIONS) => 9300000.0
 | 
			
		||||
    | (Fund(META), PAYOUTS) => 830000.0
 | 
			
		||||
    | (All, _) => sum()
 | 
			
		||||
    | (_, CHANCE_OF_EXISTENCE) => 0.0
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let xRisk = conditionals =>
 | 
			
		||||
    Prop.Value.ConditionalArray.get(conditionals, "Global Existential Event");
 | 
			
		||||
 | 
			
		||||
  // TODO: Fixe number that integral is calculated for
 | 
			
		||||
  let getGlobalCatastropheChance = dateTime => {
 | 
			
		||||
    GlobalCatastrophe.makeI(MomentRe.momentNow())
 | 
			
		||||
    |> DistPlusRenderer.Inputs.make(~distPlusIngredients=_, ())
 | 
			
		||||
    |> DistPlusRenderer.run
 | 
			
		||||
    |> E.R.bind(_, r =>
 | 
			
		||||
         r
 | 
			
		||||
         |> DistPlusTime.Integral.xToY(Time(dateTime))
 | 
			
		||||
         |> E.O.toResult("error")
 | 
			
		||||
       )
 | 
			
		||||
    |> E.R.toOption;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let make =
 | 
			
		||||
      (
 | 
			
		||||
        group: group,
 | 
			
		||||
        dateTime: MomentRe.Moment.t,
 | 
			
		||||
        currentDateTime: MomentRe.Moment.t,
 | 
			
		||||
        output: output,
 | 
			
		||||
        conditionals: array(Prop.Value.conditional),
 | 
			
		||||
      ) => {
 | 
			
		||||
    let xRisk = xRisk(conditionals);
 | 
			
		||||
    switch (output) {
 | 
			
		||||
    | DONATIONS
 | 
			
		||||
    | PAYOUTS =>
 | 
			
		||||
      let difference =
 | 
			
		||||
        calculateDifference(
 | 
			
		||||
          currentValue(group, output),
 | 
			
		||||
          dateTime,
 | 
			
		||||
          currentDateTime,
 | 
			
		||||
          yearlyMeanGrowthRateIfNotClosed(group),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
      let str =
 | 
			
		||||
        switch (xRisk) {
 | 
			
		||||
        | Some({truthValue: true}) => "0"
 | 
			
		||||
        | Some({truthValue: false}) => difference
 | 
			
		||||
        | None =>
 | 
			
		||||
          let foo =
 | 
			
		||||
            getGlobalCatastropheChance(dateTime)
 | 
			
		||||
            |> E.O.fmap(r => {
 | 
			
		||||
                 let chance = r;
 | 
			
		||||
                 let opposite = 1.0 -. r;
 | 
			
		||||
                 let reg = difference;
 | 
			
		||||
                 {j|mm(0, $reg, [$chance, $opposite])|j};
 | 
			
		||||
               });
 | 
			
		||||
          foo |> E.O.default("");
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
      let distPlusIngredients =
 | 
			
		||||
        DistPlusRenderer.Inputs.Ingredients.make(
 | 
			
		||||
          ~guesstimatorString=str,
 | 
			
		||||
          ~domain=Complete,
 | 
			
		||||
          ~unit=UnspecifiedDistribution,
 | 
			
		||||
          (),
 | 
			
		||||
        );
 | 
			
		||||
      Prop.Value.DistPlusIngredients(distPlusIngredients);
 | 
			
		||||
 | 
			
		||||
    | CHANCE_OF_EXISTENCE =>
 | 
			
		||||
      Prop.Value.DistPlusIngredients(
 | 
			
		||||
        DistPlusRenderer.Inputs.Ingredients.make(
 | 
			
		||||
          ~guesstimatorString=
 | 
			
		||||
            GuesstimatorDist.min(
 | 
			
		||||
              GlobalCatastrophe.guesstimatorString,
 | 
			
		||||
              GuesstimatorDist.logNormal(20., 2.),
 | 
			
		||||
            ),
 | 
			
		||||
          ~unit=TimeDistribution({zero: currentDateTime, unit: `years}),
 | 
			
		||||
          ~domain=RightLimited({xPoint: 100., excludingProbabilityMass: 0.3}),
 | 
			
		||||
          (),
 | 
			
		||||
        ),
 | 
			
		||||
      )
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module Interface = {
 | 
			
		||||
  open Data;
 | 
			
		||||
 | 
			
		||||
  let fundKey = "Fund";
 | 
			
		||||
  let dayKey = "Day";
 | 
			
		||||
  let outputKey = "Output";
 | 
			
		||||
 | 
			
		||||
  let choiceFromString = (s: string) =>
 | 
			
		||||
    funds |> E.A.getBy(_, r => r.name == s);
 | 
			
		||||
 | 
			
		||||
  let outputFromString = (s: string) =>
 | 
			
		||||
    switch (s) {
 | 
			
		||||
    | "donations" => DONATIONS
 | 
			
		||||
    | "exists" => CHANCE_OF_EXISTENCE
 | 
			
		||||
    | _ => PAYOUTS
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
  let run = (p: array(option(Prop.Value.t))) => {
 | 
			
		||||
    switch (p) {
 | 
			
		||||
    | [|
 | 
			
		||||
        Some(SelectSingle(fund)),
 | 
			
		||||
        Some(DateTime(intendedYear)),
 | 
			
		||||
        Some(DateTime(currentYear)),
 | 
			
		||||
        Some(SelectSingle(output)),
 | 
			
		||||
        Some(ConditionalArray(conditionals)),
 | 
			
		||||
      |] =>
 | 
			
		||||
      choiceFromString(fund)
 | 
			
		||||
      |> E.O.fmap(fund =>
 | 
			
		||||
           Model.make(
 | 
			
		||||
             fund.group,
 | 
			
		||||
             intendedYear,
 | 
			
		||||
             currentYear,
 | 
			
		||||
             outputFromString(output),
 | 
			
		||||
             conditionals,
 | 
			
		||||
           )
 | 
			
		||||
         )
 | 
			
		||||
    | _ => None
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let model: Prop.Model.t =
 | 
			
		||||
    Prop.{
 | 
			
		||||
      id: "ea-funds",
 | 
			
		||||
      name: "EA Funds: Donations & Payouts",
 | 
			
		||||
      description: "Calculate the payments and payouts of CEA Funds based on existing data.",
 | 
			
		||||
      version: "1.0.0",
 | 
			
		||||
      fileName: "EAFunds.re",
 | 
			
		||||
      author: "Ozzie Gooen",
 | 
			
		||||
      inputTypes: [|
 | 
			
		||||
        TypeWithMetadata.make(
 | 
			
		||||
          ~name=fundKey,
 | 
			
		||||
          ~type_=
 | 
			
		||||
            SelectSingle({
 | 
			
		||||
              default: Some(Array.unsafe_get(Data.funds, 0).name),
 | 
			
		||||
              options:
 | 
			
		||||
                Data.funds
 | 
			
		||||
                |> E.A.fmap((r) =>
 | 
			
		||||
                     ({name: r.name, id: r.name}: Prop.Type.selectOption)
 | 
			
		||||
                   )
 | 
			
		||||
                |> Array.to_list,
 | 
			
		||||
            }),
 | 
			
		||||
          (),
 | 
			
		||||
        ),
 | 
			
		||||
        TypeWithMetadata.make(
 | 
			
		||||
          ~name=dayKey,
 | 
			
		||||
          ~type_=
 | 
			
		||||
            DateTime({
 | 
			
		||||
              default:
 | 
			
		||||
                Some(
 | 
			
		||||
                  MomentRe.Moment.add(
 | 
			
		||||
                    ~duration=MomentRe.duration(5., `years),
 | 
			
		||||
                    MomentRe.momentNow(),
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              min:
 | 
			
		||||
                Some(
 | 
			
		||||
                  MomentRe.Moment.subtract(
 | 
			
		||||
                    ~duration=MomentRe.duration(20., `years),
 | 
			
		||||
                    MomentRe.momentNow(),
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              max:
 | 
			
		||||
                Some(
 | 
			
		||||
                  MomentRe.Moment.add(
 | 
			
		||||
                    ~duration=MomentRe.duration(20., `years),
 | 
			
		||||
                    MomentRe.momentNow(),
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
            }),
 | 
			
		||||
          (),
 | 
			
		||||
        ),
 | 
			
		||||
        TypeWithMetadata.currentYear,
 | 
			
		||||
        TypeWithMetadata.make(
 | 
			
		||||
          ~name=outputKey,
 | 
			
		||||
          ~type_=
 | 
			
		||||
            SelectSingle({
 | 
			
		||||
              default: Some("Output"),
 | 
			
		||||
              options: [
 | 
			
		||||
                {name: "Donations", id: "donations"},
 | 
			
		||||
                {name: "Funding", id: "funding"},
 | 
			
		||||
                {name: "Closing", id: "exists"},
 | 
			
		||||
              ],
 | 
			
		||||
            }),
 | 
			
		||||
          (),
 | 
			
		||||
        ),
 | 
			
		||||
        TypeWithMetadata.make(
 | 
			
		||||
          ~name="Conditionals",
 | 
			
		||||
          ~id="conditionals",
 | 
			
		||||
          ~type_=
 | 
			
		||||
            Conditionals(
 | 
			
		||||
              Prop.Type.makeConditionals(
 | 
			
		||||
                [||],
 | 
			
		||||
                [|"Global Existential Event"|],
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          (),
 | 
			
		||||
        ),
 | 
			
		||||
      |],
 | 
			
		||||
      outputTypes: [||],
 | 
			
		||||
      run,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,39 +0,0 @@
 | 
			
		|||
let guesstimatorString = "uniform(1, 100)";
 | 
			
		||||
 | 
			
		||||
let makeI = (currentDateTime: MomentRe.Moment.t) => {
 | 
			
		||||
  DistPlusRenderer.Inputs.Ingredients.make(
 | 
			
		||||
    ~guesstimatorString,
 | 
			
		||||
    ~unit=TimeDistribution({zero: currentDateTime, unit: `years}),
 | 
			
		||||
    ~domain=RightLimited({xPoint: 300.0, excludingProbabilityMass: 0.3}),
 | 
			
		||||
    (),
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
module Model = {
 | 
			
		||||
  let make = (currentDateTime: MomentRe.Moment.t) => {
 | 
			
		||||
    Prop.Value.DistPlusIngredients(makeI(currentDateTime));
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module Interface = {
 | 
			
		||||
  let dayKey = "Day";
 | 
			
		||||
 | 
			
		||||
  let run = (p: array(option(Prop.Value.t))) => {
 | 
			
		||||
    switch (p) {
 | 
			
		||||
    | [|Some(DateTime(currentYear))|] => Some(Model.make(currentYear))
 | 
			
		||||
    | _ => None
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let model: Prop.Model.t =
 | 
			
		||||
    Prop.{
 | 
			
		||||
      name: "Global Catastrophe",
 | 
			
		||||
      id: "global-catastrophe",
 | 
			
		||||
      fileName: "GlobalCatastrophe.re",
 | 
			
		||||
      description: "The chances of having at least one catastrophe per year in the future, assuming no other catastrophe until then.",
 | 
			
		||||
      version: "1.0.0",
 | 
			
		||||
      author: "Ozzie Gooen",
 | 
			
		||||
      inputTypes: [|TypeWithMetadata.currentYear|],
 | 
			
		||||
      outputTypes: [||],
 | 
			
		||||
      run,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,42 +0,0 @@
 | 
			
		|||
let guesstimatorString = age =>
 | 
			
		||||
  GuesstimatorDist.normal(72.0 -. age, 5.0 -. age *. 0.01);
 | 
			
		||||
 | 
			
		||||
let makeI = (age: float) => {
 | 
			
		||||
  DistPlusRenderer.Inputs.Ingredients.make(
 | 
			
		||||
    ~guesstimatorString=guesstimatorString(age),
 | 
			
		||||
    ~unit=TimeDistribution({zero: MomentRe.momentNow(), unit: `years}),
 | 
			
		||||
    ~domain=RightLimited({xPoint: 300.0, excludingProbabilityMass: 0.3}),
 | 
			
		||||
    (),
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module Model = {
 | 
			
		||||
  let make = (age: float) => {
 | 
			
		||||
    Prop.Value.DistPlusIngredients(makeI(age));
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module Interface = {
 | 
			
		||||
  let ageKey = "age";
 | 
			
		||||
 | 
			
		||||
  let run = (p: array(option(Prop.Value.t))) => {
 | 
			
		||||
    switch (p) {
 | 
			
		||||
    | [|Some(FloatPoint(age)), Some(SelectSingle(sex))|] =>
 | 
			
		||||
      Some(Model.make(age))
 | 
			
		||||
    | _ => None
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let model: Prop.Model.t =
 | 
			
		||||
    Prop.{
 | 
			
		||||
      name: "Death Time",
 | 
			
		||||
      id: "human-lifespan",
 | 
			
		||||
      fileName: "Human.re",
 | 
			
		||||
      description: "When will you die?",
 | 
			
		||||
      version: "1.0.0",
 | 
			
		||||
      author: "Ozzie Gooen",
 | 
			
		||||
      inputTypes: [|TypeWithMetadata.age, TypeWithMetadata.sex|],
 | 
			
		||||
      outputTypes: [||],
 | 
			
		||||
      run,
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,20 +1,3 @@
 | 
			
		|||
type route =
 | 
			
		||||
  | Model(string);
 | 
			
		||||
 | 
			
		||||
let routeToPath = route =>
 | 
			
		||||
  switch (route) {
 | 
			
		||||
  | Model(modelId) => "/m/" ++ modelId
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
module Models = {
 | 
			
		||||
  let all = [|
 | 
			
		||||
    EAFunds.Interface.model,
 | 
			
		||||
    GlobalCatastrophe.Interface.model,
 | 
			
		||||
    Human.Interface.model,
 | 
			
		||||
  |];
 | 
			
		||||
  let getById = id => E.A.getBy(all, r => r.id == id);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module Styles = {
 | 
			
		||||
  open Css;
 | 
			
		||||
  let h3 = style([fontSize(`em(1.5)), marginBottom(`em(1.5))]);
 | 
			
		||||
| 
						 | 
				
			
			@ -30,51 +13,9 @@ module Table = {
 | 
			
		|||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  module Item = {
 | 
			
		||||
    [@react.component]
 | 
			
		||||
    let make = (~model: Prop.Model.t, ~children) => {
 | 
			
		||||
      <div className=TableStyles.row>
 | 
			
		||||
        <div className={TableStyles.col()}>
 | 
			
		||||
          <a
 | 
			
		||||
            href={routeToPath(Model(model.id))}
 | 
			
		||||
            onClick={e => {
 | 
			
		||||
              e->ReactEvent.Synthetic.preventDefault;
 | 
			
		||||
              ReasonReactRouter.push(routeToPath(Model(model.id)));
 | 
			
		||||
            }}>
 | 
			
		||||
            children
 | 
			
		||||
          </a>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className={TableStyles.col(~f=3.0, ())}>
 | 
			
		||||
          {model.description |> R.ste}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className={TableStyles.col()}> {model.author |> R.ste} </div>
 | 
			
		||||
      </div>;
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  module ColumnsTitles = {
 | 
			
		||||
    [@react.component]
 | 
			
		||||
    let make = () => {
 | 
			
		||||
      <div className=TableStyles.row>
 | 
			
		||||
        <div className={TableStyles.col()}> {"Name" |> R.ste} </div>
 | 
			
		||||
        <div className={TableStyles.col(~f=3.0, ())}>
 | 
			
		||||
          {"Description" |> R.ste}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className={TableStyles.col()}> {"Author" |> R.ste} </div>
 | 
			
		||||
      </div>;
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  [@react.component]
 | 
			
		||||
  let make = () => {
 | 
			
		||||
    <>
 | 
			
		||||
      <h3 className=Styles.h3> {"Probability Models" |> R.ste} </h3>
 | 
			
		||||
      <ColumnsTitles />
 | 
			
		||||
      {Models.all
 | 
			
		||||
       |> E.A.fmap((model: Prop.Model.t) => {
 | 
			
		||||
            <Item model key={model.id}> {model.name |> R.ste} </Item>
 | 
			
		||||
          })
 | 
			
		||||
       |> ReasonReact.array}
 | 
			
		||||
    </>;
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user