ramda-fantasy
Version:
Fantasy Land compatible types for easy integration with Ramda
247 lines (201 loc) • 7.13 kB
Markdown
# State
The `State` type can be used to store some state along with a computation.
## Construction
`State` instances should be obtained via the `get`, `gets`, `put`, and `modify`
static properties on the `State` object. These instances describe the different
ways to access and modify the stateful computation that will eventually be
evaluated and are described in further detail below.
A `State` transformer is also available via `State.T` which can be used to
extend some monad with stateful behaviour.
## Interaction
`State` instances are primarily interacted with and composed via the `chain`
method of the various static instances available on the `State` type object. To
access the current state, `State.get` is a static instance that can be used to
provide the state to the `chain`, `ap` and `map`. Similarly, `State.gets(fn)`
can provide the state transformed by the provided `fn` function. To change the
state of the computation, `State.put(newValue)` can be used to replace the
existing state with `newValue`. The current state can also be transformed by
providing a transformation function to `State.modify(transformFn)`.
Once a `State` instance is defined, an initial seed state can be provided to
either the `eval` or `exec` methods to evaluate the computation and return the
result of the computation or the final state, respectively. Alternatively, the
`run` method can be called to return both the result and the final state within
a `Tuple` instance.
```js
// An example deterministic pseudorandom number generator
// see: https://en.wikipedia.org/wiki/Linear_congruential_generator
// type RNG a = State Integer a
// rng :: RNG Float
const rng = State.get.chain(seed => {
const newSeed = (seed * 1103515245 + 12345) & 0x7FFFFFFF;
const randVal = (newSeed >>> 16) / 0x7FFF;
return State.put(newSeed).map(_ => randVal);
});
rng.eval(42); // From initial seed of 42: 0.5823236793115024
rng.eval(42); // Repeating produces the same value: 0.5823236793115024
rng.exec(42); // `exec` returns the next seed: 1250496027
rng.eval(1250496027); // A different seed: 0.5198217719046602
// Chain together to pass the new seed to the next RNG
// pair :: RNG a -> RNG (Tuple a a)
const pair = rng => rng.chain(a => rng.chain(b => State.of(Tuple(a, b))));
pair(rng).eval(42); // Tuple(0.5823236793115024, 0.5198217719046602)
// Map to produce transformed random values from 1 to 6
// rollDie :: RNG Integer
const rollDie = rng.map(n => Math.ceil(n * 6));
// rollDice :: RNG (Tuple Integer Integer)
const rollDice = pair(rollDie);
rollDice.eval(123); // Tuple(2, 5)
```
## Reference
### Constructors
#### `State`
```hs
:: (s -> Identity (Tuple a s)) -> State s a
```
Constructs a `State` instance that represent a pure computation from some state
to a new state and a result. Note this constructor requires the given function
to return an `Identity` instance. It is generally recommended to use the static
properties and methods provided on the `State` object rather than using this
constructor.
#### `State.T`
```hs
:: Monad m => { of :: a -> m a } -> (s -> m (Tuple a s)) -> StateT s m a
```
Constructs a `StateT` instance that represent a computation from some state to a
new state and a result in the context of some other monad. It is generally
recommended to use the static properties and methods provided on the `State`
object rather than using this constructor.
### Static properties
#### `State.get`
```hs
:: State s s
```
A static `State` instance that retrieves the current state.
#### `StateT.get`
```hs
:: Monad m => StateT s m s
```
A static `StateT` instance that retrieves the current state.
### Static methods
#### `State.gets`
```hs
:: (s -> a) -> State s a
```
Returns a `State` instance the retrieves the current state transformed by the
given function.
#### `StateT.gets`
```hs
:: Monad m => (s -> a) -> StateT s m a
```
Returns a `State` instance the retrieves the current state transformed by the
given function.
#### `State.put`
```hs
:: s -> State s a
```
Returns a `State` instance the stores the provided state.
#### `StateT.put`
```hs
:: Monad m => s -> StateT s m a
```
Returns a `StateT` instance the stores the provided state
#### `State.modify`
```hs
:: (s -> s) -> State s a
```
Returns a `State` instance the modifies the stored state with the provided
function.
#### `StateT.modify`
```hs
:: Monad m => (s -> s) -> StateT s m a
```
Returns a `StateT` instance the modifies the stored state with the provided
function.
#### `State.of`
```hs
:: a -> State s a
```
Returns a `State` instance that will evaluate to the provided value.
#### `StateT.of`
```hs
:: Monad m => a -> StateT s m a
```
Returns a `StateT` instance that will evaluate to the provided value.
#### `StateT.lift`
```hs
:: Moand m => m a -> StateT s m a
```
Lifts the given monad into a `StateT` instance.
### Instance methods
#### `state.run`
```hs
:: State s a ~> s -> Tuple a s
```
Runs the `State` instance, seeded by the provided value and returns the final
state along with the result in a `Tuple`.
#### `stateT.run`
```hs
:: Monad m => StateT s m a ~> s -> m Tuple(a, s)
```
Runs the `StateT` instance, seeded by the provided value and returns the final
state along with the result in a `Tuple` within the underlying monad type of the
transformer.
#### `state.eval`
```hs
:: State s a ~> s -> a
```
Runs the `State` instance, seeded by the provided value and returns the result.
#### `stateT.eval`
```hs
:: Monad m => StateT s m a ~> s -> m a
```
Runs the `StateT` instance, seeded by the provided value and returns the result
in the context of the underlying monad type of the transformer.
#### `state.exec`
```hs
:: State s a ~> s -> s
```
Runs the `State` instance, seeded by the provided value and returns the final
state.
#### `stateT.exec`
```hs
:: Monad m => StateT s m a ~> s -> m s
```
Runs the `StateT` instance, seeded by the provided value and returns the final
state in the context of the underlying monad type of the transformer.
#### `state.map`
```hs
:: State s a ~> (a -> b) -> State s b
```
Transforms the eventual result of the `State` instance with the provided
function.
#### `stateT.map`
```hs
:: Monad m => StateT s m a ~> (a -> b) -> StateT s m b
```
Transforms the eventual result of the `StateT` instance with the provided
function.
#### `state.ap`
```hs
:: State s (a -> b) ~> State s a -> State s b
```
Applies the resulting function of this `State` instance to the result of the
provided `State` instance to produce a new `State` instance.
#### `stateT.ap`
```hs
:: Monad m => StateT s m (a -> b) ~> StateT s m a -> StateT s m b
```
Applies the resulting function of this `StateT` instance to the result of the
provided `StateT` instance to produce a new `StateT` instance.
#### `state.chain`
```hs
:: State s a ~> (a -> State s b) -> State s b
```
Creates a new `State` instance by applying the given function to the result of
this `State` instance.
#### `stateT.chain`
```hs
:: StateT s m a ~> (a -> StateT s m b) -> StateT s m b
```
Creates a new `StateT` instance by applying the given function to the result of
this `StateT` instance.