Skip to content

Instantly share code, notes, and snippets.

@Pet3ris
Created August 14, 2020 22:15
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 Pet3ris/6918587f9dc39a79d92852819aa3815e to your computer and use it in GitHub Desktop.
Save Pet3ris/6918587f9dc39a79d92852819aa3815e to your computer and use it in GitHub Desktop.
Lazy promise queue implementation in ReasonML
// Lazy PromiseQueue implementation
type pair('a) = ('a, t('a))
and t('a) = {next: Lazy.t(Js.Promise.t(option(pair('a))))};
let build = promise => {next: promise};
let empty: t('a) = lazy(Js.Promise.resolve(None)) |> build;
let cons = (p: Lazy.t(Js.Promise.t('a)), pq: t('a)) => {
lazy(p |> Lazy.force |> Js.Promise.then_(a => Js.Promise.resolve(Some((a, pq))))) |> build;
};
let make = (p: Lazy.t(Js.Promise.t('a))): t('a) => cons(p, empty);
let next = (pq: t('a)): Lazy.t(Js.Promise.t(option(pair('a)))) => pq.next;
let rec before = (p: t('a), q: t('a)): t('a) =>
lazy(p.next
|> Lazy.force
|> Js.Promise.then_(ppair =>
switch (ppair) {
| Some((first, pq)) =>
Js.Promise.resolve(Some((first, before(pq, q))))
| None => q.next |> Lazy.force
}
))
|> build;
let rec fromArrayP = (all: array(Lazy.t(Js.Promise.t('a)))): t('a) => {
switch (Belt.Array.get(all, 0)) {
| Some(first) => cons(first, fromArrayP(Belt.Array.sliceToEnd(all, 1)))
| None => empty
};
};
let rec mapP = (pq: t('a), f: 'a => Lazy.t(Js.Promise.t('b))): t('b) =>
lazy(pq.next
|> Lazy.force
|> Js.Promise.then_(ppair =>
switch (ppair) {
| Some((first, pq)) =>
let rest = mapP(pq, f);
first
|> f
|> Lazy.force
|> Js.Promise.then_(first =>
Js.Promise.resolve(Some((first, rest)))
);
| None => Js.Promise.resolve(None)
}
))
|> build;
let rec flatMapP = (pq: t('a), f: 'a => array(Lazy.t(Js.Promise.t('b)))): t('b) =>
lazy(pq.next
|> Lazy.force
|> Js.Promise.then_(ppair =>
switch (ppair) {
| Some((first, pq)) =>
let rest = flatMapP(pq, f);
first -> f -> fromArrayP -> (firsts => before(firsts, rest).next) -> Lazy.force;
| None => Js.Promise.resolve(None)
}
))
|> build;
let rec take = (pq: t('a), n: int): Js.Promise.t(array('a)) =>
if (n == 0) {
Js.Promise.resolve([||]);
} else {
pq.next
|> Lazy.force
|> Js.Promise.then_(ppair =>
switch (ppair) {
| Some((first, pq)) =>
let a = [|first|];
take(pq, n - 1)
|> Js.Promise.then_(rest =>
Js.Promise.resolve(Belt.Array.concat(a, rest))
);
| None => Js.Promise.resolve([||])
}
);
};
type t('a);
let fromArrayP: array(Lazy.t(Js.Promise.t('a))) => t('a);
let mapP: (t('a), 'a => Lazy.t(Js.Promise.t('b))) => t('b);
let flatMapP: (t('a), 'a => array(Lazy.t(Js.Promise.t('b)))) => t('b);
let take: (t('a), int) => Js.Promise.t(array('a));
// Example use:
// let output = arrayOfNumbers
// -> PromiseQueue.fromArrayP
// -> PromiseQueue.flatMapP(f)
// -> PromiseQueue.mapP(f)
// -> PromiseQueue.take(20)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment