### 10 releases (breaking)

0.8.0 | May 17, 2024 |
---|---|

0.7.0 | Apr 24, 2024 |

0.6.0 | Apr 18, 2024 |

0.5.0 | Apr 12, 2024 |

0.1.2 | Mar 21, 2024 |

#**714** in Algorithms

**MIT/Apache**

34KB

492 lines

# rand-functors

provides an abstraction over different ways of evaluating random processes expressed as functions of both deterministic and stochastic data. This is achieved using a combination of a type-based version of the Strategy pattern and functional programming's Functor pattern.`rand-functors`

A motivating problem for this crate is the code duplication present across these two functions modelling the same random process:

`use` `rand``::``prelude``::``*``;`
`fn` `next_state``(``mut` `state``:` `u8``)`` ``->` `u8` `{`
state `=` state`.``wrapping_add``(``random``(``)``)``;`
`if` `random``(``)` `{`
state `%=` `3``;`
`}`
state
`}`
`fn` `next_states``(``state``:` `u8``)`` ``->` `Vec``<``u8``>` `{`
`let` `mut` out`:` `Vec``<``_``>` `=` `(``0``..``=``255``)``.``map``(``|``r``|` `state``.``wrapping_add``(`r`)``)``.``collect``(``)``;`
out`.``append``(``&``mut` out`.``iter``(``)``.``copied``(``)``.``map``(``|``i``|` `i ``%` `3``)``.``collect``(``)``)``;`
out
`}`

While these functions may appear different, the same random process is embedded in both of them. A random

is added to `u8`

and then, if a random `state`

is `bool`

, the state will be set to itself modulo 3.`true`

This redundant implementation of the random process could pose issues during a refactor. If one decides to change the

to a `%=` `3`

in `%=` `5`

, he or she will need to make the corresponding update in `next_state`

.`next_states`

Using

, these two functions can be combined as:`rand-functors`

`use` `rand``::``prelude``::``*``;`
`use` `rand_functors``::``{`Functor`,` RandomStrategy`}``;`
`fn` `next_state``<`S`:` RandomStrategy`>``(``state``:` `u8``)`` ``->` `S``::``Functor``<``u8``>` `{`
`let` `mut` out `=` `S``::`fmap_rand`(``Functor``::`pure`(`state`)``,` `&``mut` `thread_rng``(``)``,` `|``s``,` `r``|` `{`
s`.``wrapping_add``(`r`)`
`}``)``;`
out `=` `S``::`fmap_rand`(`out`,` `&``mut` `thread_rng``(``)``,` `|``s``,` `r``|` `if` r `{` s `%` `3` `}` `else` `{` s `}``)``;`
out
`}`

This new implementation makes

generic over a `next_state``RandomStrategy`

. Its return type is also changed to the `S`

associated with `Functor`

. Inside, `S`

is converted from `state`

to `u8`

. The remainder of the function is essentially the same as the original `S ::`Functor

`<``u8``>``next_state`

, but each operation a random sample is now wrapped in a call to `S``::`fmap_rand

. Calling `next_state``::``<`Sampler`>``(`s`)`

would be equivalent to calling `next_state``(`s`)`

before. Similarly, one could call `next_state``::``<`Enumerator`>``(`s`)`

instead of using `next_states``(`s`)`

, which would require maintaining a separate implementation of the same core process.At present,

only supports random variables that are either of type `rand-functors`

or of a numeric type occupying no more than 16 bits by default. However, it is possible to implement all the requisite traits for a custom data type.`bool`

#### Dependencies

~0.3–0.8MB

~14K SLoC