Monads, functors etc. for Clojure.
I was writing various other libraries (yet to be released) and most of the time they ended up needing efficient Functor and Monad protocols. Having copies of those protocols in every library is clearly silly. I did not want the extra indirection and magic of Cats (currying because of Applicative Functors, MonadContexts in dynamic Vars, monads that just wrap fns) or the loose typing of algo.monads (macros instead of protocols, the State monad is just a raw fn instead of having a dedicated type).
So Monnit was born. Of course there are more monad libraries but they seem to have a different focus (Fluokitten), be abandoned and to be honest, NIH.
do
-notation-like
mlet
macro) in monnit.corenil
and NullPointerException
sthrow
and uncaught exceptionsctx
parameter; also an alternative to dynamic VarsA little State monad benchmark (in /bench
) seems to support my performance
intuitions:
$ clj -A:bench
Clojure 1.10.3
> (require '[monnit.benchmarks :as b]reload)
nil
> (b/benchmark-labeling 10)
# clojure.core
Evaluation count : 143400 in 60 samples of 2390 calls.
Execution time mean : 418,939803 µs
Execution time std-deviation : 645,276885 ns
Execution time lower quantile : 417,622749 µs ( 2,5%)
Execution time upper quantile : 419,771713 µs (97,5%)
Overhead used : 2,266132 ns
Found 1 outliers in 60 samples (1,6667 %)
low-severe 1 (1,6667 %)
Variance from outliers : 1,6389 % Variance is slightly inflated by outliers
# monnit.state
Evaluation count : 153600 in 60 samples of 2560 calls.
Execution time mean : 391,324179 µs
Execution time std-deviation : 967,126577 ns
Execution time lower quantile : 390,299234 µs ( 2,5%)
Execution time upper quantile : 393,342059 µs (97,5%)
Overhead used : 2,266132 ns
Found 4 outliers in 60 samples (6,6667 %)
low-severe 1 (1,6667 %)
low-mild 1 (1,6667 %)
high-mild 2 (3,3333 %)
Variance from outliers : 1,6389 % Variance is slightly inflated by outliers
# clojure.algo.monads/state-m
Evaluation count : 153600 in 60 samples of 2560 calls.
Execution time mean : 391,098502 µs
Execution time std-deviation : 346,384313 ns
Execution time lower quantile : 390,393749 µs ( 2,5%)
Execution time upper quantile : 391,640304 µs (97,5%)
Overhead used : 2,266132 ns
# cats.monad.state
Evaluation count : 8580 in 60 samples of 143 calls.
Execution time mean : 7,025305 ms
Execution time std-deviation : 12,159509 µs
Execution time lower quantile : 7,002061 ms ( 2,5%)
Execution time upper quantile : 7,043491 ms (97,5%)
Overhead used : 2,266132 ns
Here Monnit and algo.monads are about 7% faster than the vanilla Clojure version, probably because the latter uses PersistentVectors and destructuring. I was pleased to see that Monnit matches the performance of algo.monads while keeping the State monad type (types, actually) distinct like Cats.
The Cats State monad is about 17 times slower than the baseline, probably due to the indirections mentioned earlier. To be fair, the State monad does not seem to be much of a priority for Cats; it was even removed at some point, then re-added.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close