Created
June 10, 2021 17:52
-
-
Save idkjs/4cbdbdecb000ddc6285cf3e1bec79c81 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Source: http://jonase.github.io/nil-recur/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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