Skip to content

Instantly share code, notes, and snippets.

@tonyhb
Created January 11, 2018 00:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tonyhb/9c6a1bd44fb21170ac43413bd5993f1d to your computer and use it in GitHub Desktop.
Save tonyhb/9c6a1bd44fb21170ac43413bd5993f1d to your computer and use it in GitHub Desktop.
fsm/dfa
/* result represents either a success or an error for an operation. It can hold
a resource of any type - ie. a user, treatment etc. */
type result('resource) =
| Ok('resource)
| Error('resource, string);
/* Event represents a single event within our system */
type event('data, 'resource) = {
/* The ID of the user authoring the event */
author: string,
/* The string name of the event */
name: string,
/* The input data to the event. For example, when submitting a TP form this will
be the TP data */
data: 'data,
/* The resource that the event modifies. This may be a single type or a struct
containing many types for modification */
resource: 'resource,
/* The apply function, which takes the event data and modifies the resource. This
returns the newly modified resource and a Result type representing whether the
event application was a success. */
apply: ('data, 'resource) => result('resource)
};
/**
Input data
==========
**/
/* A super basic TP form */
type tp = {
stages: int,
cadence: int
};
/* A super basic type form */
type onboarding = {concern: string};
/**
System types (ie. models
============
**/
type status =
| Registered
| PreConsultation
| PostConsultation
| Consented
| InTreatment
| Dismissed
| Graduated;
type user = {
name: string,
status,
onboarding: option(onboarding)
};
type refinement = {
number: int,
stages: int,
cadence: int
};
type treatment = {
refinements: list(refinement),
startDate: option(float),
endDate: option(float)
};
/**
Events
======
These comprise our FSM/DFA
**/
/* submitOnboarding generates a new event for submitting the onboarding form during
registration.
It accepts an author name (ie. their ID in a real system), the onboarding data
plus the user to modify
*/
let submitOnboarding = (author, onboarding: onboarding, user: user) => {
author,
name: "submit_onboarding",
/* the input is an onboarding form */
data: onboarding,
/* it modifies a user model */
resource: user,
/* apply runs the modification */
apply: (onboarding, user) =>
/** Only allow the onboarding form to be submitted for certain user statuses **/
(
switch user.status {
/* Update the "onboarding" property of the user */
| Registered => Ok({...user, onboarding: Some(onboarding)})
| PreConsultation => Ok({...user, onboarding: Some(onboarding)})
| _ => Error(user, "User doesn't have a valid status to apply onboarding event")
}
)
};
let submitTP = (author, tp: tp, tx: treatment) => {
author,
name: "submit_tp",
data: tp,
resource: tx,
apply: (tp, tx) => Error(tx, "TODO")
};
/**
DEMOS
=====
**/
/** The basic FSM applicator **/
let apply = (event: event('a, 'b)) => event.apply(event.data, event.resource);
let result =
submitOnboarding(
"Kjeld",
{concern: "gaps"},
{name: "tony", status: Registered, onboarding: None}
)
|> apply;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment