By Artyom Kazak aka @availablegreen
January 3, 2021
I work as a Haskell consultant at Monadfix. I've been using Haskell for 10 years. Here are the libraries/tools I use.
Other lists like this:
Ping me on Twitter if you have more, or want your own list to be added.
Missing items: logging (everything sucks?), RPC (I used gRPC-haskell but I think it's not recommended anymore; there's also Mu-Haskell?), metrics, various math stuff, error handling, validation, JWT, OAuth, image/audio manipulation, machine learning, GUIs, compilation to JS (likely GHCJS?), SMTP/IMAP (probably HaskellNet?), URL manipulation (is there anything better than network-uri?), profiling, memory leak search (info table profiling will be nice when it lands in GHC), time/distance/etc units, bytestring builders (see the haskell-perf shootout), memoization (chimera for dense and memoize for sparse), temp files (temporary? UnliftIO.Temporary?)
|Area||What and why|
Well, and sometimes searching through GitHub, too.
|GHC Core viewer|
It passes the right flags to GHC for me, and highlights the Core, too.
Most custom preludes redefine
Furthermore, in my experience prohibiting unsafe functions from being used doesn't work because people do
record-dot-preprocessor gives me nice access syntax, and lenses give me nice
If you can't use the
Finally, AFAIK large records have quadratic typechecking time (as of Jan 2021). A super-recent solution to this problem is Well-Typed's large-records library.
jrec (the improved fork of superrecord).
I wrote jrec for internal Juspay purposes, it's faster, it's easier to maintain, it's predictable, I like it. Vinyl has too much stuff in it.
I wrote microlens, but I see no reason to use it for apps and I don't get why people do. For libraries, not having a ton of dependencies feels nice though.
I don't think optics is better enough for me to switch, but who knows.
Uniplate is a bit slow but is amazing for walking through ASTs and other complex structures. It saves me a ton of time.
I have examples at How to walk a complex AST generically.
When I need to write a generics-based library (e.g. JSON serialization, etc), I reach for 'generics-eot' because it is super easy to use. See Generics are simple: write your own ToJSON.
I haven't actually evaluated 'containers' vs 'unordered-containers', but I think the latter is faster, and anything I want to use as a key is usually
A great library. It's fast and I can do atomic updates, which is all I want.
No particular reason. 'split' is very standard and 'extra' is written by Neil Mitchell so I trust it.
I wrote fmt. It's fast, it has all the formatting primitives I want, and it has the least annoying way to write format strings:
There are more typesafe libraries, but eh. So far I think I haven't regretted going with the most standard library.
|File manipulation and scripting|
Again, the most standard libraries.
If I want to zip something, I do
I might try typed-process next time, which is supposed to be strictly better than 'process', and see how it goes.
I know that a lot of people like turtle for scripting, but I really didn't like it. Figuring out how to do things with 'turtle' was too hard when I tried it.
'optparse-generic' is like 'optparse-applicative', except that instead of defining everything by hand you can just define an ADT for your command-line interface and it will generate the parser by itself.
It has limitations, which I just ignore. Yeah, I can't fully control the resulting interface, but I don't care at this point.
I am not qualified to compare streaming libraries, and I suspect all of them are either painful, incomplete, full of gotchas, or all three. When I used conduit, it was reasonably fine.
If I had to go for the fastest, I would take a look at streamly.
It just works and is nicer than blaze-html. A bunch of other HTML libraries popped up recently, but I didn't even look at them.
|HTML parsing and scraping|
I don't think you have many other choices. There is also scalpel, which is a wrapper around tagsoup, but I never used it.
Once you realize that you can manipulate type-level trees with type families, Servant becomes easy and nice and delightful. I can write custom combinators for things if I want. I can walk the API and collect whatever info I want about it.
I like 'wreq' but somehow don't fully trust it, so I use 'http-client-tls' whenever I'm doing anything other than scripting.
I don't like req because it seems to be overengineered.
BazQux uses it and they seem to have handled all the corner-cases in existence. It seems to be both the easiest to use and the most production-y library that exists, so I'm using it.
Anti-recommendation: download. Doesn't handle TLS, and, well, doesn't even compile for me.
aws only covers a small subset of AWS, and 'amazonka' covers everything but is sometimes buggy. Pick your poison. (At Wire we picked 'amazonka' and it was mostly fine, but there were some bugs re/ S3 that we didn't know how to work around.)
For Google Cloud, there is gogol from the author of 'amazonka'.
Probably the most common choice now and it's fine for my usecases.
I like 'serialise' because it uses CBOR as the format, and so I'm not locked into Haskell if I want to work with it.
If I have to operate with an already existing format, then 'cereal', but something better might have appeared in the meantime.
zstd if I control the format, and otherwise I don't know.
My understanding is that Facebook's 'zstd' (aka Zstandard) is state of the art. I like using anything that is state of the art.
Tweet at me if you have recommendations re/ other compression formats.
|Hashing and cryptography|
'cryptonite' is a huge box of crypto primitives. I don't think anything else implements all the things I need, so I either have to go hunting for libraries, or "go with cryptonite for everything". I do the latter.
I also worked with Vincent, the author of cryptonite, and I trust him, so there's that.
Usually I don't care and so I go with 'random'. If I do care, it's almost always in the direction of "I need something more secure", and 'random' is not secure for anything crypto-related or generally anything that should be unguessable.
I haven't actually used pcg-random in anger, but I think it's state of the art when it comes to fast random number generators, and as I mentioned, I really really like state of the art. It's likely better than the Mersenne twister.
Usually, if I want regexes, it's because I want convenience for myself or for my users. This means PCRE over Posix. I think 'pcre-heavy' is alright, but while writing this post I found 'pcre2' and it seems to be better still.
If I want my regexes to be understandable, then I don't actually want regexes, I want parsers. Hence 'replace-megaparsec'.
Anti-recommendations: regex-tdfa and text-icu. Both are buggy. 'regex-tdfa' in particular is based on a tricky algorithm and the original author does not maintain it anymore, so there isn't much chance that any logic bugs in it will be fixed.
|Unicode text manipulation|
'text-icu' binds to the mature and powerful ICU library. Everybody have been using it for a long while. However, a) 'text-icu' hasn't been updated since 2015, b) depending on foreign libraries can be a pain. This is why the community is trying to write pure Haskell replacements for the most commonly needed ICU features.
Note that 'unicode-transforms' is (AFAIK) slightly faster than 'text-icu' for normalization. 'unicode-collation' is 4x slower (as of Apr 2021).
However, I just looked and it seems that 'commonmark' is better than both.
A nice thing is that you can convert commonmark's types into Pandoc types (see commonmark-pandoc) and then use Pandoc's entire ecosystem.
'async' is not super super easy to use, but it's fine.
I also like atomic updates a lot, so I use 'stm' very liberally. My monad stack usually has a
I usually don't use parallelism (
|Retrying IO actions|
Not qualified to compare with other libs, but 'retry' is good.
named instead of records or newtypes.
If you want to make functions like
ghc-lib-parser, hands down.
ghc-lib-parser is a copy of GHC's own parser, updated regularly. Ormolu uses it. HLint uses it. There is no reason to use (buggy) haskell-src-exts anymore.
If I want to pretty-print AST into a source form, or something like that, I go with 'prettyprinter'. I haven't tried other libraries much, but it says "modern" and "maintained well", so I like it.
Sometimes using a C preprocessor (
When I do anything even remotely nontrivial, I make sure that my code is preprocessed with 'cpphs' and not the system-wide preprocessor.
|DIY build system|
Shake is a Haskell DSL for writing build systems. If you want something Make-like but don't want to learn a new DSL, you might like Shake. I used it for a static site generator and it was nice.
Update Apr 3, 2021: tasty-bench is a new lightweight library with Criterion-compatible API and an out-of-the-box ability to compare benchmark results with previous results. The 'text' library has recently switched to 'tasty-bench'. I might consider it for a next project.
|Date and time|
I don't like 'time'. A lot of people try 'time' because it's the standard, and then say "huh, this is harder than I thought". This said, I don't know of any other popular options. The last release of thyme, for instance, was in 2014.
'clock' is a good option for timestamps, because it lets you decide on the precision/speed tradeoff.