Skip to content

Instantly share code, notes, and snippets.

@idkjs
Created June 10, 2021 17:52
Show Gist options
  • Save idkjs/4cbdbdecb000ddc6285cf3e1bec79c81 to your computer and use it in GitHub Desktop.
Save idkjs/4cbdbdecb000ddc6285cf3e1bec79c81 to your computer and use it in GitHub Desktop.
Source: http://jonase.github.io/nil-recur/
type contact = {
id: int64,
email: string,
};
module Contacts = Map.Make(Int64);
type email = {
from_addr: string,
to_addr: string,
title: string,
body: string,
};
let email1 = {
from_addr: "flint@example.com",
to_addr: "strax@example.com",
title: "Hi!",
body: "...",
};
let email2 = {
from_addr: "strax@example.com",
to_addr: "flint@example.com",
title: "Re: Hi!",
body: "...",
};
// let x = compare(email1, email2);
// x->Js.log;
module Email = {
type t = email;
let compare = compare;
};
module Inbox = Set.Make(Email);
type contact_action =
| AddContact(contact)
| RemoveContact(int64);
type inbox_action =
| AddToInbox(email)
| RemoveFromInbox(email);
type action =
| ContactAction(contact_action)
| InboxAction(inbox_action)
| EmailSentAction(email);
let contact_reducer = (contacts, action) =>
switch (action) {
| ContactAction(AddContact(contact)) =>
Contacts.add(contact.id, contact, contacts)
| ContactAction(RemoveContact(id)) => Contacts.remove(id, contacts)
| _ => contacts
};
let inbox_reducer = (inbox, action) =>
switch (action) {
| InboxAction(ia) =>
switch (ia) {
| AddToInbox(email) => Inbox.add(email, inbox)
| RemoveFromInbox(email) => Inbox.remove(email, inbox)
}
| _ => inbox
};
let sent_reducer = (sent, action) =>
switch (action) {
| EmailSentAction(email) => [email, ...sent]
| _ => sent
};
type email_store = {
inbox: Inbox.t,
sent: list(email),
};
type store = {
contacts: Contacts.t(contact),
emails: email_store,
};
let email_reducer = (email_store, action) => {
inbox: inbox_reducer(email_store.inbox, action),
sent: sent_reducer(email_store.sent, action),
};
let root_reducer = (store, action) => {
contacts: contact_reducer(store.contacts, action),
emails: email_reducer(store.emails, action),
};
let initial_store = {
contacts: Contacts.empty,
emails: {
sent: [],
inbox: Inbox.empty,
},
};
let actions = [
EmailSentAction({
from_addr: "flint@example.com",
to_addr: "strax@example.com",
title: "Hi!",
body: "...",
}),
ContactAction(AddContact({id: 101L, email: "vastra@example.com"})),
InboxAction(
AddToInbox({
from_addr: "strax@example.com",
to_addr: "flint@example.com",
title: "Re: Hi",
body: "...",
}),
),
ContactAction(AddContact({id: 102L, email: "flint@example.com"})),
ContactAction(RemoveContact(101L)),
ContactAction(AddContact({id: 103L, email: "strax@example.com"})),
];
// put these in `rtop` to see the output
let result = List.fold_left(root_reducer, initial_store, actions);
Contacts.bindings(result.contacts);
Inbox.elements(result.emails.inbox);
Reason # #use "src/Reducers.re"
;
type contact = {
id: int64,
email: string,
};
module Contacts:
{
type key = int64;
type t('a) = Map.Make(Int64).t('a);
let empty: t('a);
let is_empty: t('a) => bool;
let mem: (key, t('a)) => bool;
let add: (key, 'a, t('a)) => t('a);
let update:
(key, option('a) => option('a),
t('a)) => t('a);
let singleton: (key, 'a) => t('a);
let remove: (key, t('a)) => t('a);
let merge:
((key, option('a), option('b)) =>
option('c),
t('a), t('b)) => t('c);
let union:
((key, 'a, 'a) => option('a),
t('a), t('a)) => t('a);
let compare:
(('a, 'a) => int, t('a), t('a)) =>
int;
let equal:
(('a, 'a) => bool, t('a), t('a)) =>
bool;
let iter:
((key, 'a) => unit, t('a)) => unit;
let fold:
((key, 'a, 'b) => 'b, t('a), 'b) =>
'b;
let for_all:
((key, 'a) => bool, t('a)) => bool;
let exists:
((key, 'a) => bool, t('a)) => bool;
let filter:
((key, 'a) => bool, t('a)) => t('a);
let filter_map:
((key, 'a) => option('b), t('a)) =>
t('b);
let partition:
((key, 'a) => bool, t('a)) =>
(t('a), t('a));
let cardinal: t('a) => int;
let bindings: t('a) => list((key, 'a));
let min_binding: t('a) => (key, 'a);
let min_binding_opt:
t('a) => option((key, 'a));
let max_binding: t('a) => (key, 'a);
let max_binding_opt:
t('a) => option((key, 'a));
let choose: t('a) => (key, 'a);
let choose_opt:
t('a) => option((key, 'a));
let split:
(key, t('a)) =>
(t('a), option('a), t('a));
let find: (key, t('a)) => 'a;
let find_opt:
(key, t('a)) => option('a);
let find_first:
(key => bool, t('a)) => (key, 'a);
let find_first_opt:
(key => bool, t('a)) =>
option((key, 'a));
let find_last:
(key => bool, t('a)) => (key, 'a);
let find_last_opt:
(key => bool, t('a)) =>
option((key, 'a));
let map: ('a => 'b, t('a)) => t('b);
let mapi:
((key, 'a) => 'b, t('a)) => t('b);
let to_seq: t('a) => Seq.t((key, 'a));
let to_seq_from:
(key, t('a)) => Seq.t((key, 'a));
let add_seq:
(Seq.t((key, 'a)), t('a)) => t('a);
let of_seq: Seq.t((key, 'a)) => t('a);
};
type email = {
from_addr: string,
to_addr: string,
title: string,
body: string,
};
let email1: email =
{from_addr: "flint@example.com",
to_addr: "strax@example.com",
title: "Hi!", body: "..."};
let email2: email =
{from_addr: "strax@example.com",
to_addr: "flint@example.com",
title: "Re: Hi!", body: "..."};
let x: int = -1;
File "src/Reducers.re", line 26, characters 1-3:
26 | ntAction({
^^
Error: Unbound value |.
Reason # #use "src/Reducers.re"
;
type contact = {
id: int64,
email: string,
};
module Contacts:
{
type key = int64;
type t('a) = Contacts.t('a);
let empty: t('a);
let is_empty: t('a) => bool;
let mem: (key, t('a)) => bool;
let add: (key, 'a, t('a)) => t('a);
let update:
(key, option('a) => option('a),
t('a)) => t('a);
let singleton: (key, 'a) => t('a);
let remove: (key, t('a)) => t('a);
let merge:
((key, option('a), option('b)) =>
option('c),
t('a), t('b)) => t('c);
let union:
((key, 'a, 'a) => option('a),
t('a), t('a)) => t('a);
let compare:
(('a, 'a) => int, t('a), t('a)) =>
int;
let equal:
(('a, 'a) => bool, t('a), t('a)) =>
bool;
let iter:
((key, 'a) => unit, t('a)) => unit;
let fold:
((key, 'a, 'b) => 'b, t('a), 'b) =>
'b;
let for_all:
((key, 'a) => bool, t('a)) => bool;
let exists:
((key, 'a) => bool, t('a)) => bool;
let filter:
((key, 'a) => bool, t('a)) => t('a);
let filter_map:
((key, 'a) => option('b), t('a)) =>
t('b);
let partition:
((key, 'a) => bool, t('a)) =>
(t('a), t('a));
let cardinal: t('a) => int;
let bindings: t('a) => list((key, 'a));
let min_binding: t('a) => (key, 'a);
let min_binding_opt:
t('a) => option((key, 'a));
let max_binding: t('a) => (key, 'a);
let max_binding_opt:
t('a) => option((key, 'a));
let choose: t('a) => (key, 'a);
let choose_opt:
t('a) => option((key, 'a));
let split:
(key, t('a)) =>
(t('a), option('a), t('a));
let find: (key, t('a)) => 'a;
let find_opt:
(key, t('a)) => option('a);
let find_first:
(key => bool, t('a)) => (key, 'a);
let find_first_opt:
(key => bool, t('a)) =>
option((key, 'a));
let find_last:
(key => bool, t('a)) => (key, 'a);
let find_last_opt:
(key => bool, t('a)) =>
option((key, 'a));
let map: ('a => 'b, t('a)) => t('b);
let mapi:
((key, 'a) => 'b, t('a)) => t('b);
let to_seq: t('a) => Seq.t((key, 'a));
let to_seq_from:
(key, t('a)) => Seq.t((key, 'a));
let add_seq:
(Seq.t((key, 'a)), t('a)) => t('a);
let of_seq: Seq.t((key, 'a)) => t('a);
};
type email = {
from_addr: string,
to_addr: string,
title: string,
body: string,
};
let email1: email =
{from_addr: "flint@example.com",
to_addr: "strax@example.com",
title: "Hi!", body: "..."};
let email2: email =
{from_addr: "strax@example.com",
to_addr: "flint@example.com",
title: "Re: Hi!", body: "..."};
module Email:
{
type t = email;
let compare: ('a, 'a) => int;
};
module Inbox:
{
type elt = email;
type t = Set.Make(Email).t;
let empty: t;
let is_empty: t => bool;
let mem: (elt, t) => bool;
let add: (elt, t) => t;
let singleton: elt => t;
let remove: (elt, t) => t;
let union: (t, t) => t;
let inter: (t, t) => t;
let disjoint: (t, t) => bool;
let diff: (t, t) => t;
let compare: (t, t) => int;
let equal: (t, t) => bool;
let subset: (t, t) => bool;
let iter: (elt => unit, t) => unit;
let map: (elt => elt, t) => t;
let fold:
((elt, 'a) => 'a, t, 'a) => 'a;
let for_all: (elt => bool, t) => bool;
let exists: (elt => bool, t) => bool;
let filter: (elt => bool, t) => t;
let filter_map:
(elt => option(elt), t) => t;
let partition:
(elt => bool, t) => (t, t);
let cardinal: t => int;
let elements: t => list(elt);
let min_elt: t => elt;
let min_elt_opt: t => option(elt);
let max_elt: t => elt;
let max_elt_opt: t => option(elt);
let choose: t => elt;
let choose_opt: t => option(elt);
let split: (elt, t) => (t, bool, t);
let find: (elt, t) => elt;
let find_opt: (elt, t) => option(elt);
let find_first: (elt => bool, t) => elt;
let find_first_opt:
(elt => bool, t) => option(elt);
let find_last: (elt => bool, t) => elt;
let find_last_opt:
(elt => bool, t) => option(elt);
let of_list: list(elt) => t;
let to_seq_from: (elt, t) => Seq.t(elt);
let to_seq: t => Seq.t(elt);
let add_seq: (Seq.t(elt), t) => t;
let of_seq: Seq.t(elt) => t;
};
type contact_action =
AddContact(contact)
| RemoveContact(int64);
type inbox_action =
AddToInbox(email)
| RemoveFromInbox(email);
type action =
ContactAction(contact_action)
| InboxAction(inbox_action)
| EmailSentAction(email);
let contact_reducer:
(Contacts.t(contact), action) =>
Contacts.t(contact) = <fun>;
let inbox_reducer:
(Inbox.t, action) => Inbox.t = <fun>;
let sent_reducer:
(list(email), action) => list(email) =
<fun>;
type email_store = {
inbox: Inbox.t,
sent: list(email),
};
type store = {
contacts: Contacts.t(contact),
emails: email_store,
};
let email_reducer:
(email_store, action) => email_store =
<fun>;
let root_reducer: (store, action) => store =
<fun>;
let initial_store: store =
{contacts: <abstr>,
emails: {inbox: <abstr>, sent: []}};
let actions: list(action) =
[EmailSentAction({from_addr:
"flint@example.com",
to_addr:
"strax@example.com",
title: "Hi!",
body: "..."}),
ContactAction((AddContact({id: 101L,
email:
"vastra@example.com"}))),
InboxAction((AddToInbox({from_addr:
"strax@example.com",
to_addr:
"flint@example.com",
title: "Re: Hi",
body: "..."}))),
ContactAction((AddContact({id: 102L,
email:
"flint@example.com"}))),
ContactAction((RemoveContact(101L))),
ContactAction((AddContact({id: 103L,
email:
"strax@example.com"})))];
Reason # let result = List.fold_left (root_reducer ,initial_store, actions);
let result: store =
{contacts: <abstr>,
emails:
{inbox: <abstr>,
sent:
[{from_addr: "flint@example.com",
to_addr: "strax@example.com",
title: "Hi!", body: "..."}]}};
Reason # Contacts.bindings(result.contacts)
;
- : list((int64, contact)) =
[(102L,
{id: 102L, email: "flint@example.com"}),
(103L,
{id: 103L, email: "strax@example.com"})]
Reason # Inbox.elements(result.emails.inbox);
- : list(email) =
[{from_addr: "strax@example.com",
to_addr: "flint@example.com",
title: "Re: Hi", body: "..."}]
Reason #
┌──────────┬──────────┬──────────────┬─────┐
│AddContact│AddToInbox│Afl_instrument│Alias│
└──────────┴──────────┴──────────────┴─────┘
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment