Module Relude_AsyncData

Relude.AsyncData contains an variant type t('a) for representing the different states in which a value can be during an asynchronous data load. Because the type only has a single type parameter 'a, it cannot represent failures by default, but you can choose to use any type for 'a, including option('b) (for data that may or may not load), result('b, 'e) (for data that can fail to load), etc.

If you need to represent an error condition along with the success condition, see Relude_AsyncResult.

The variant type has the following constructors:

This type is similar to the Elm RemoteData type, with a few key differences:

  1. AsyncData does not inherently have the concept of failure (again, see Relude_AsyncResult if that's something you want).
  2. AsyncData has a Reloading('a) state which can be used to indicate that data is being refreshed/reloaded/saved while retaining a current (or previous) value. E.g. if you have loaded some data, and need to reload it but want to keep the current value around for display purposes, you might use the Reloading('a) state rather than the Loading state which does not carry any data.

AsyncData has instances of various typeclasses like Functor, Applicative, Monad etc. which unlock the ability to compose and combine AsyncData values using functions like map2-map5, flatMap, traverse, etc.

For example, if you have multiple pieces of data that are being loaded asynchronously, you can combine the results of several AsyncData values into a single tupled AsyncData value using map2, map3, etc. or any of the other combinators.

type t('a) =
| Init
| Loading
| Reloading('a)
| Complete('a)
;

AsyncData represents the state of data that is being loaded asynchronously. While Promise and IO represent the effect of loading that data, AsyncData represents what that data looks like at one particular snapshot in time. This is particularly useful when storing application state (e.g. in a React component).

By default, this type does not represent failures. If you want to represent the possibility for an async value to fail, you can use a result in the 'a type (or see AsyncResult, which does this for you).

The reason for this is that not all async data loading mechanisms will necessarily fail.

The other interesting bit is that Reloading can be used if you already have data, but you need to reload the data to get a new value.

let init: t('a);

Constructs an Init value

let loading: t('a);

Constructs a Loading value

let reloading: 'a => t('a);

Constructs a Reloading value containing the given value

let complete: 'a => t('a);

Constructs a Reloading value containing the given value

let isInit: a. t('a) => bool;

Checks if this AsyncData value is Init

let isLoading: a. t('a) => bool;

Checks if this AsyncData value is Loading

let isReloading: a. t('a) => bool;

Checks if this AsyncData value is Reloading with any value

let isComplete: a. t('a) => bool;

Checks if this AsyncData value is Complete with any value

let isBusy: a. t('a) => bool;

Checks if this AsyncData value is working (Loading or Reloading)

let isIdle: a. t('a) => bool;

Checks if this AsyncData value is not working (Init or Complete)

let isEmpty: a. t('a) => bool;

Checks if this AsyncData value is Init or Loading

let isNotEmpty: a. t('a) => bool;

Checks if this AsyncData value is Reloading or Complete

let toBusy: a. t('a) => t('a);

Creates a new AsyncData by transitioning the given AsyncData into a busy state (Loading or Reloading), and carrying over the internal data if available.

let toIdle: a. t('a) => t('a);

Creates a new AsyncData by transitioning the given AsyncData into an idle state (Init or Complete), and carrying over the internal data if available.

let getValue: a. t('a) => option('a);

Get a value of type 'a, using the Complete value if the AsyncData is complete, or the last known complete value in Reloading.

let getReloading: a. t('a) => option('a);

Get Some value of type 'a only from the Reloading state, and None in all other cases, including Complete

let getComplete: a. t('a) => option('a);

Get Some value of type 'a only from the Complete state, and None in all other cases, including Reloading.

let fold: a b. 'b => 'b => ('a => 'b) => ('a => 'b) => t('a) => 'b;

Fold the AsyncData into a new type by providing a strict value or function to handle each case.

let foldLazy: a b. (unit => 'b) => (unit => 'b) => ('a => 'b) => ('a => 'b) => t('a) => 'b;

Fold the AsyncData into a new value by providing a function to handle each case.

let foldByValue: a b. 'b => ('a => 'b) => t('a) => 'b;

Fold the AsyncData into a new value by providing a strict value to use when there is no data, or function to handle when there is data.

let foldByValueLazy: a b. (unit => 'b) => ('a => 'b) => t('a) => 'b;

Fold the AsyncData into a new value by providing a lazy value to use when there is no data, or function to handle when there is data.

let map: a b. ('a => 'b) => t('a) => t('b);

Maps a pure function over the value contained by Reloading or Complete

module Functor: BsBastet.Interface.FUNCTOR with type Functor.t('a) = t('a);
include { ... };
module BsFunctorExtensions: { ... };
let flipMap: Functor.t('a) => ('a => 'b) => Functor.t('b);
let void: Functor.t('a) => Functor.t(unit);
let voidRight: 'a => Functor.t('b) => Functor.t('a);
let voidLeft: Functor.t('a) => 'b => Functor.t('b);
let flap: Functor.t(('a => 'b)) => 'a => Functor.t('b);
let tap: a. (unit => unit) => (unit => unit) => ('a => unit) => ('a => unit) => t('a) => t('a);

Applies a side effect function for each case of the variant (Init, Loading, Reloading, Complete)

let tapInit: a. (unit => unit) => t('a) => t('a);

Applies a side effect function if the value is Init

let tapLoading: a. (unit => unit) => t('a) => t('a);

Applies a side effect function if the value is Loading

let tapReloading: a. ('a => unit) => t('a) => t('a);

Applies a side effect function if the value is Reloading

let tapComplete: a. ('a => unit) => t('a) => t('a);

Applies a side effect function if the value is Complete

let tapEmpty: a. (unit => unit) => t('a) => t('a);

Applies a side effect function if the value is Init or Loading

let tapNotEmpty: a. ('a => unit) => t('a) => t('a);

Applies a side effect function if the value is Reloading or Complete

let tapByValue: a. (unit => unit) => ('a => unit) => t('a) => t('a);

Applies a side effect function for the empty case and the not-empty case

let apply: a b. t(('a => 'b)) => t('a) => t('b);

Applies a wrapped function to the value contained by Reloading or Complete

module Apply: BsBastet.Interface.APPLY with type Apply.t('a) = t('a);
include { ... };
module BsApplyExtensions: { ... };
let applyFirst: Apply.t('a) => Apply.t('b) => Apply.t('a);
let applySecond: Apply.t('a) => Apply.t('b) => Apply.t('b);
let map2: ('a => 'b => 'c) => Apply.t('a) => Apply.t('b) => Apply.t('c);
let map3: ('a => 'b => 'c => 'd) => Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t('d);
let map4: ('a => 'b => 'c => 'd => 'e) => Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t('d) => Apply.t('e);
let map5: ('a => 'b => 'c => 'd => 'e => 'f) => Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t('d) => Apply.t('e) => Apply.t('f);
let tuple2: Apply.t('a) => Apply.t('b) => Apply.t(('a, 'b));
let tuple3: Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t(('a, 'b, 'c));
let tuple4: Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t('d) => Apply.t(('a, 'b, 'c, 'd));
let tuple5: Apply.t('a) => Apply.t('b) => Apply.t('c) => Apply.t('d) => Apply.t('e) => Apply.t(('a, 'b, 'c, 'd, 'e));
let mapTuple2: ('a => 'b => 'c) => (Apply.t('a), Apply.t('b)) => Apply.t('c);
let mapTuple3: ('a => 'b => 'c => 'd) => (Apply.t('a), Apply.t('b), Apply.t('c)) => Apply.t('d);
let mapTuple4: ('a => 'b => 'c => 'd => 'e) => (Apply.t('a), Apply.t('b), Apply.t('c), Apply.t('d)) => Apply.t('e);
let mapTuple5: ('a => 'b => 'c => 'd => 'e => 'f) => (Apply.t('a), Apply.t('b), Apply.t('c), Apply.t('d), Apply.t('e)) => Apply.t('f);
let pure: a. 'a => t('a);

Lifts a pure value into the context of an AsyncData, in the Complete state

module Applicative: BsBastet.Interface.APPLICATIVE with type Applicative.t('a) = t('a);
include { ... };
module BsApplicativeExtensions: { ... };
let liftA1: ('a => 'b) => Applicative.t('a) => Applicative.t('b);
let when_: bool => Applicative.t(unit) => Applicative.t(unit);
let unless: bool => Applicative.t(unit) => Applicative.t(unit);
let all: list(Applicative.t('a)) => Applicative.t(list('a));
let bind: a b. t('a) => ('a => t('b)) => t('b);

Applies a monadic function to the value contained by Reloading or Complete

module Monad: BsBastet.Interface.MONAD with type Monad.t('a) = t('a);
include { ... };
module BsMonadExtensions: { ... };
let flatMap: ('a => Monad.t('b)) => Monad.t('a) => Monad.t('b);
let flatten: Monad.t(Monad.t('a)) => Monad.t('a);
let composeKleisli: ('a => Monad.t('b)) => ('b => Monad.t('c)) => 'a => Monad.t('c);
let flipComposeKleisli: ('b => Monad.t('c)) => ('a => Monad.t('b)) => 'a => Monad.t('c);
let liftM1: ('a => 'b) => Monad.t('a) => Monad.t('b);
let when_: Monad.t(bool) => Monad.t(unit) => Monad.t(unit);
let unless: Monad.t(bool) => Monad.t(unit) => Monad.t(unit);
let alt: a. t('a) => t('a) => t('a);

alt for AsyncData tries to find the most advanced state between two AsyncData values in terms of completeness.

module Alt: BsBastet.Interface.ALT with type Alt.t('a) = t('a);
include { ... };
let orElse: fallback:Alt.t('a) => Alt.t('a) => Alt.t('a);
let eqBy: a. ('a => 'a => bool) => t('a) => t('a) => bool;

Indicates if two AsyncData values are in the same state, and that the contained values are equal.

module Eq: (E: BsBastet.Interface.EQ) => BsBastet.Interface.EQ;
let showBy: a. ('a => string) => t('a) => string;

Converts an AsyncData value to a string, using the given function to convert the contained value to a string.

module Show: (S: BsBastet.Interface.SHOW) => BsBastet.Interface.SHOW;
module Infix: { ... };