└── haskell-notes.md /haskell-notes.md: -------------------------------------------------------------------------------- 1 | # Learn Me a Haskell, Finally 2 | 3 | **(or: Notes of a Haskell Beginner)** 4 | 5 | Notes about things I keep forgetting, or continue to find confusing, while 6 | learning Haskell. 7 | 8 | This is not meant as a comprehensive guide, but rather is a scattered 9 | collection of useful information and resources. These notes cover some 10 | meta/toolchain stuff as well aspects of the language itself. 11 | 12 | This is a living document -- I'll update it as my understanding of a concept 13 | solidifies, or if something relevant changes. 14 | 15 | (Note: I'm writing this selfishly. Primarily, *I* am the document's target 16 | audience. Apologies if I make some assumptions throughout. Also, I'm new to 17 | Haskell, so I'm probably wrong about everything. Sorry again!) 18 | 19 | 20 | ## Table of contents 21 | 22 | * [Getting started](#getting-started) 23 | * [Installation / Toolchain stuff](#installation--toolchain-stuff) 24 | * [Initial setup](#initial-setup) 25 | * [Testing it out](#testing-it-out) 26 | * ["Real" projects](#real-projects) 27 | * [A special note about stack install](#a-special-note-about-stack-install) 28 | * [Stackage](#stackage) 29 | * [One big fat Stack caveat: HLS issues](#one-big-fat-stack-caveat-hls-issues) 30 | * [Symptoms of the problem](#symptoms-of-the-problem) 31 | * [Resolving / working around Stack+HLS issues](#resolving--working-around-stackhls-issues) 32 | * [Further reading about these issues](#further-reading-about-these-issues) 33 | * [Editor stuff](#editor-stuff) 34 | * [VS Code](#vs-code) 35 | * [Neovim](#neovim) 36 | * [Other editors](#other-editors) 37 | * [Static analysis](#static-analysis) 38 | * [Pattern matching](#pattern-matching) 39 | * [Function argument pattern matching and case statements](#function-argument-pattern-matching-and-case-statements) 40 | * [Guards](#guards) 41 | * [Pattern matching vs guards](#pattern-matching-vs-guards) 42 | * [Pattern matching references](#pattern-matching-references) 43 | * [Monad stuff](#monad-stuff) 44 | * [Some useful monads](#some-useful-monads) 45 | * [Monad transformers](#monad-transformers) 46 | * [Using monad transformers](#using-monad-transformers) 47 | * [Order of composition](#order-of-composition) 48 | * [Lifting](#lifting) 49 | * [Monad transformer libraries](#monad-transformer-libraries) 50 | * [mtl and transformer type classes](#mtl-and-transformer-type-classes) 51 | * [Monad transformer resources](#monad-transformer-resources) 52 | * [Error handling](#error-handling) 53 | * [Exceptions](#exceptions) 54 | * [(Avoid) partial functions](#avoid-partial-functions) 55 | * [Stack traces?](#stack-traces) 56 | * [Language extensions](#language-extensions) 57 | * [Everyday programming tasks](#everyday-programming-tasks) 58 | * [CLI arguments](#cli-arguments) 59 | * [A special note on variable-length argument lists](#a-special-note-on-variable-length-argument-lists) 60 | * [Other libraries](#other-libraries) 61 | * [Unit testing](#unit-testing) 62 | * [JSON parsing](#json-parsing) 63 | * [Parsing in general](#parsing-in-general) 64 | * [Time and dates](#time-and-dates) 65 | * [HTTP requests](#http-requests) 66 | * [Working with text](#working-with-text) 67 | * [Debugging](#debugging) 68 | * [Concurrency](#concurrency) 69 | * [Miscellaneous good reads](#miscellaneous-good-reads) 70 | * [Document meta](#document-meta) 71 | 72 | 73 | ## Getting started 74 | 75 | These notes won't be enough to get you started. If you're *brand* new, get 76 | yourself a book: 77 | 78 | * [Get Programming in 79 | Haskell](https://www.manning.com/books/get-programming-with-haskell) by Will 80 | Kurt. I thought this was fantastic. Great balance of theory and practice, 81 | fun examples, &c. The goal is to get you fluent enough to start building 82 | "weekend projects" in Haskell. (But also to understand what the hell you're 83 | doing.) 84 | * [Programming in Haskell](https://www.cs.nott.ac.uk/~pszgmh/pih.html) by 85 | Graham Hutton. Just started working through this one. Drier, but a good 86 | complement to *Get Programming in Haskell*. Highly recommended by the 87 | Haskell community. 88 | * [Haskell Programming from First Principles](https://haskellbook.com/). It's 89 | a damn encyclopedia, 1200 pages. I haven't read it yet. 90 | * [Real World Haskell](http://book.realworldhaskell.org/). Free! But old. 91 | Could be valuable, but don't start here. 92 | * [Learn You a Haskell](http://www.learnyouahaskell.com/). I love this book. A 93 | really amazing (and also free!) reference, though it too is a bit old these 94 | days. Still fantastic to read, but beware that certain info might be 95 | out-of-date. 96 | 97 | Aside from books, this [CIS 194: Intro to 98 | Haskell](https://www.seas.upenn.edu/~cis1940/fall16/) course is supposedly a 99 | very good intro. And free! 100 | 101 | There's also [Write Yourself a Scheme in 48 102 | Hours](https://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours), 103 | which aims to be an introduction to Haskell. However, the more I learn about 104 | Haskell, the more I'd hesitate to recommend this tutorial to a beginner. Aside 105 | from being extremely fast-paced in its explanations, its code also tends to be 106 | quite ugly. (Not super well-factored, filled with confusing "magical" 107 | one-liners, lots of partial functions and incomplete pattern-matches, etc.) 108 | 109 | Still, it's an interesting tutorial nonetheless. And writing your own language 110 | -- what a cool first project! (Or fifth project, or whatever.) It might be a 111 | good exercise for an intermediate Haskeller to go through and clean up the 112 | code themselves... 113 | 114 | 115 | ## Installation / Toolchain stuff 116 | 117 | Toolchain stuff. A nightmare in any language. And the current state of any 118 | language's ecosystem is the result of years of evolution, working to solve 119 | problems that beginners like us have no context for. 120 | 121 | Oh well! Whatever! Gotta start somewhere! Here's what's worked for me so far. 122 | Easy to set up, easy to maintain. 123 | 124 | ### Initial setup 125 | 126 | 0. Don't install GHC with your system's package manager. If you already did, 127 | uninstall it. Fewer surprises down the road this way. 128 | 1. Install [GHCup](https://www.haskell.org/ghcup/). 129 | 2. Fire it up (`ghcup tui`) and use it to install GHC (the compiler), HLS 130 | (language server, used for IDE-like features in your editor), and 131 | (probably) Stack. (More on Stack later.) It will install cabal 132 | automatically, I believe. (More on cabal later too.) 133 | 3. If you're unsure about which versions to install, you can go by what GHCup 134 | marks as "recommended". (Note that you can still use different versions of 135 | GHC in your specific projects -- you're not "locked in" with this. It's 136 | also very easy to install/uninstall different versions with GHCup. AND you 137 | can have multiple versions installed simultaneously. So don't stress about 138 | this step.) 139 | 4. Put `~/.ghcup/bin` in your path, probably. (Or whatever the equivalent 140 | directory is on your system. I'm on Ubuntu.) 141 | 142 | That's it for initial setup. You can keep everything updated easily with 143 | GHCup, and everything it does/installs is centralized to `~/.ghcup` (or your 144 | system's equivalent). If you screw it all up and want to start fresh, just 145 | blow that directory away. No harm. 146 | 147 | ### Testing it out 148 | 149 | Now you can, e.g., run `ghci` from your terminal and poke around. Or use `ghc` 150 | to compile/interpret your one-off Haskell scripts. This is effectively your 151 | "system" version of GHC (thought it's confined to your home dir, not actually 152 | installed system-wide). 153 | 154 | That alone is probably enough to get you most of the way through beginner 155 | tutorials, and even most beginner books. 156 | 157 | ### "Real" projects 158 | 159 | ...but eventually you'll want to build real projects. Can o' worms. 160 | 161 | There's this whole "Stack or cabal" thing. Also, Stack *uses* cabal. Also, 162 | "Stack" refers to a couple of distinct ideas, sort of? And so does cabal? I 163 | don't have full context. Again, here's what got me started. 164 | 165 | Assuming you installed Stack as part of the steps above: 166 | 167 | 1. `stack new cool-project-name`. This creates a fresh directory from a 168 | default project template. Good enough for the likes of us, for now. 169 | 2. `cd cool-project-name`. Poke around. 170 | 3. `stack build`. This'll install dependencies, do initial setup if any is 171 | required, generate some project files, etc. Note that Stack will also 172 | install its own version of GHC for your project, depending on the config in 173 | your `stack.yaml` file. More on this later. These versions go in 174 | `~/.stack`, or your system's equivalent. (You don't have to worry about 175 | them, or do anything special to use them. Stack takes care of it.) 176 | 4. `stack exec cool-project-name-exe`. Run your code! (I personally popped 177 | into my `package.yaml` and got rid of that `-exe` extension because it 178 | looked weird to me, but YMMV.) 179 | 180 | I'm not going to go too in-depth here. I highly recommend *Get Programming in 181 | Haskell*, which uses Stack for all the projects in the latter half of the book 182 | and provides some great insight throughout. 183 | 184 | **NOTE:** Before you get too deep with Stack, you should be aware of [one very 185 | important caveat related to the Haskell Language Server](#one-big-fat-stack-caveat-hls-issues). 186 | This may ultimately influence your decision to go with Stack or Cabal as a 187 | build system for your future projects. (That said, it shouldn't stop you with 188 | playing around with Stack for now.) 189 | 190 | Some other useful stuff: 191 | 192 | * [The Stack intro user guide](https://docs.haskellstack.org/en/stable/tutorial/) 193 | * [stack.yaml versus package.yaml versus a Cabal 194 | file](https://docs.haskellstack.org/en/stable/topics/stack_yaml_vs_cabal_package_file/) 195 | * Stack uses a tool called [hpack](https://github.com/sol/hpack) to generate 196 | cabal files. I had to poke around in hpack's docs to solve some early 197 | project problems. You might too. 198 | * ["Why is stack not 199 | cabal?"](https://www.fpcomplete.com/blog/2015/06/why-is-stack-not-cabal/), a 200 | good article with some historical context for the whole stack/cabal 201 | situation. 202 | 203 | ### A special note about `stack install` 204 | 205 | Most tutorials I found suggest that you need to `stack install` your 206 | dependencies. **This is false!** Adding a dependency to your `package.yaml` 207 | file is *all* you need to do. Running `stack build` will do the rest. I don't 208 | know why this rumor is so rampant. 209 | 210 | The `stack install` command does only *one* thing: it copies binaries to your 211 | local binary directory. That's it! Odds are you don't want to do that ever, 212 | except for the occasional utility that you'll use *outside of the context of 213 | your project*. 214 | 215 | See [this excellent section of the Stack user 216 | guide](https://docs.haskellstack.org/en/stable/tutorial/stack_build_synonyms/#the-stack-install-command-and-copy-bins-option) 217 | for more information and clarity. 218 | 219 | ### Stackage 220 | 221 | [Stackage](https://www.stackage.org/) seems like a great idea to me. "Stable 222 | Haskell package sets", or "A distribution of compatible Haskell packages from 223 | Hackage that build together". In short, you get a versioned set of the 224 | most-used Haskell packages that are known to work well together, *and* with a 225 | given version of GHC. 226 | 227 | By default when you `stack new` a new project, it depends on the latest LTS 228 | release of stackage. (You can change this by passing an arg to `stack new` or 229 | changing the resolver in your `stack.yaml` file. But you probably don't need 230 | to.) 231 | 232 | There's an LTS for every major GHC version and plenty of minor versions. In 233 | practice, this has worked great for me so far. The only minor downside is 234 | that, typically, the stackage LTS won't be on the absolute latest version of 235 | GHC. (Since the whole package set needs to be vetted/compatible with that 236 | version.) If you care, you can use one of the nightly stackage releases to get 237 | the latest/greatest. If it works for you, you're good to go. 238 | 239 | (You can use packages that aren't in stackage too, of course. But I haven't 240 | needed to yet. It's a solid foundation.) 241 | 242 | ### One big fat Stack caveat: HLS issues 243 | 244 | I've wholeheartedly recommended Stack [above](#real-projects), and there's a 245 | good reason: it's a fantastic tool. **HOWEVER,** there is one major caveat 246 | which bears mentioning: 247 | 248 | **You will run into occasional, annoying issues with the Haskell Language 249 | Server when working on Stack projects. These issues do *not* occur with Cabal 250 | projects.** This may influence your decision to go with Stack or Cabal as your 251 | build tool of choice. 252 | 253 | Specifically, you'll notice these issues when working in Stack projects with 254 | multiple "components". For example, the default Stack projects contains 255 | components for `lib` (aka `src`), `app`, and `test`. 256 | 257 | (**Note:** If you're just getting started and don't want to get into the weeds 258 | yet, feel free to [skip to the next section](#editor-stuff) of the doc!) 259 | 260 | #### Symptoms of the problem 261 | 262 | You will find at times that updates you've made in one component will *not* be 263 | reflected in other components, according to HLS. (For example, if you've added 264 | a field to a data type in `src`, HLS will *not* complain if that field is 265 | still missing in source files within `app` and `test`.) 266 | 267 | The compiler (and therefore `stack build`, etc.) will still detect and 268 | complain about these changes. The issue is solely within your editor, due to 269 | [various communication issues](https://github.com/commercialhaskell/stack/issues/6154) 270 | between HLS and Stack which have yet to be resolved. 271 | 272 | In other cases, you might spot mysterious errors at the top of some source 273 | files (things like `failed to load packages, cannot satisfy -package 274 | `, for example). These errors will prevent HLS from working in the 275 | given file. Alternatively, you may simply notice HLS not working at all, but 276 | without displaying any errors. 277 | 278 | The root of all these issues is the same, and thankfully, the workarounds are 279 | also all the same. 280 | 281 | #### Resolving / working around Stack+HLS issues 282 | 283 | Apologies for the wishy-washy nature of these instructions. It's not 100% 284 | clear to me why *some* of these steps work only *some* of the time. 285 | 286 | 1. Run `stack build` and restart the language server. (There's a command to 287 | "Restart Language Server" in VS Code. In neovim, the command is 288 | `:LspRestart`.) You may or may not need to `stack clean`, or even `stack 289 | purge`, beforehand. Note that if your code is in a bad state, you **may 290 | need to fix compilation errors so it can successfully build** before the 291 | above will work. This is especially annoying to do without a working 292 | language server :( 293 | 2. If that doesn't work, try [clearing the HLS build 294 | cache](https://haskell-language-server.readthedocs.io/en/latest/troubleshooting.html#clearing-hls-s-build-cache), 295 | then repeating the above steps. (TL;DR: `rm -rf ~/.cache/hie-bios/`) 296 | 3. If *that* doesn't work, try the above steps, but additionally restart your 297 | editor as well, not just the language server. 298 | 299 | You may find it easiest to just do all three steps right off the bat, as I do, 300 | for the most consistent results. But note that the issue will occur again in 301 | the future as your code changes, and you'll need to repeat the above steps. 302 | 303 | **Bonus setup steps, which *might* help lessen these issues moving forward:** 304 | 305 | 1. Use a locally-compiled version of HLS, built with the same GHC version as 306 | your project. See [the HLS docs](https://haskell-language-server.readthedocs.io/en/latest/troubleshooting.html#static-binaries) 307 | for more details. GHCup makes this very easy! (e.g. `ghcup compile hls -v 308 | 2.9.0.0 --ghc 9.6.5`) 309 | 2. Provide an explicit `hie.yaml` file in your project. To start with, this 310 | can be as simple as: 311 | ```yaml 312 | cradle: 313 | stack: 314 | ``` 315 | Again, see [the HLS docs](https://haskell-language-server.readthedocs.io/en/latest/configuration.html#examples-of-explicit-hie-yaml-configurations) 316 | for more details. (Note that for at least one of my projects, this was not 317 | sufficient. See [the comments in my hie.yaml](https://github.com/keithfancher/tvmv/blob/master/hie.yaml) 318 | file for more details.) 319 | 3. Use Cabal instead of Stack. I personally prefer the UX of Stack, but, at 320 | least for now, the HLS integration with Cabal is tighter and these issues 321 | don't occur. If you'd like to try migrating an existing project from Stack 322 | to Cabal, there's [a handy tool](https://github.com/hasufell/stack2cabal) 323 | that makes it very straightforward. 324 | 325 | #### Further reading about these issues 326 | 327 | - [HLS troubleshooting page](https://haskell-language-server.readthedocs.io/en/latest/troubleshooting.html#problems-with-multi-component-support-using-stack): 328 | "Problems with multi component support using stack". 329 | - [Stack github issue](https://github.com/commercialhaskell/stack/issues/6154): "Improve stack support for HLS". 330 | - [HLS github issue](https://github.com/haskell/haskell-language-server/issues/366) for the same problem. 331 | - Various other semi-related github issues: [HLS#735](https://github.com/haskell/haskell-language-server/issues/735), [HLS#3932](https://github.com/haskell/haskell-language-server/issues/3923), [HLS#3738](https://github.com/haskell/haskell-language-server/issues/3738). 332 | - [A related Reddit thread](https://www.reddit.com/r/haskell/comments/yr09pb/hls_stack_bizarre_redherring_error_about_ghcide/): "HLS + Stack = bizarre red-herring error about ghcide versions". 333 | - [A related discussion on the Haskell Discourse](https://discourse.haskell.org/t/stack-and-hls-questions-about-the-present-and-future/10275): "Stack and HLS, questions about the present and future". 334 | 335 | ### Editor stuff 336 | 337 | Odds are you can use your favorite text editor and it'll work just fine! And 338 | thanks to the magic of the [language server 339 | protocol](https://microsoft.github.io/language-server-protocol/) generally, and the 340 | [haskell-language-server](https://haskell-language-server.readthedocs.io/en/latest/features.html) 341 | specifically, you can get pretty close to a full IDE experience, if you're 342 | into that kind of thing. 343 | 344 | #### VS Code 345 | 346 | VS Code works pretty damn well with Haskell *almost* out of the box. Install: 347 | 348 | * the main Haskell plugin and 349 | * the Haskell syntax highlighting plugin 350 | 351 | ...and you're good. You'll need to do a *little* bit of configuring -- 352 | basically point the Haskell plugin to your GHCup installation, which it will 353 | use to manage the language server installation(s). It's an easy way to get 354 | started! 355 | 356 | #### Neovim 357 | 358 | Any modern vim/neovim setup will give you comparable results, with a bit more 359 | tweaking of course. For neovim, I recommend: 360 | 361 | * The [haskell-vim](https://github.com/neovimhaskell/haskell-vim) plugin, 362 | which greatly improves syntax highlighting and indentation for Haskell over 363 | the defaults that ship with vim. 364 | * The [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) plugin, which 365 | includes predefined configs for various language servers. (Assuming you want 366 | the IDE-like features the language server provides.) See [the 367 | haskell-language-server 368 | section](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#hls) 369 | of the plugin's docs for more specific details. 370 | * The [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) 371 | plugin, which makes it dead-simple to use fancy newfangled 372 | [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) parsers for 373 | Haskell (or any other supported language). Tree-sitter offers a bunch of cool 374 | benefits which are worth looking into, but at the bare minimum it provides 375 | *much* improved syntax highlighting. It's great. 376 | 377 | These plugins (or equivalent) might be just as good with (a newish version of) 378 | vanilla vim, but I don't know for sure. Give it a shot! YMMV. 379 | 380 | #### Other editors 381 | 382 | Hopefully it goes without saying that other editors are also probably fine. I 383 | just don't have direct experience. Emacs is always a cool choice. In my Scala 384 | days, I had pretty good luck with IntelliJ, which has a Haskell plugin. Use 385 | whatever works. 386 | 387 | ### Static analysis 388 | 389 | Especially if you're a beginner, and *especially* if you don't have people 390 | reviewing your code, static analysis can be a big help. Suss out 391 | anti-patterns, teach you some common idioms, prevent common classes of bugs, 392 | etc. 393 | 394 | Here's what I've been using so far, all of which have been (their own brand 395 | of) helpful: 396 | 397 | * [hlint](https://hackage.haskell.org/package/hlint), via the 398 | [haskell-language-server](https://haskell-language-server.readthedocs.io/en/latest/features.html#hlint-hints). 399 | You get this for free by default if you use the language server. If not, 400 | it's still worth checking out. 401 | * [stan](https://github.com/kowainik/stan), an opinionated static analyzer 402 | which occasionally gives *slightly* controversial advice. Very valuable for 403 | a beginner! Not necessarily because you need to blindly follow every hint it 404 | offers, but because it will surface potential issues you didn't even know 405 | existed. (For example, it never occurred to me that `length` could be a 406 | partial function! But, I'm also not used to dealing with infinite lists...) 407 | Like hlint, Stan can be used as a standalone CLI tool or as a plugin for the 408 | Haskell Language Server (though it may be disabled by default, depending on 409 | your HLS version). 410 | * Not quite "static analysis," but: `stack build --pedantic`. Same as enabling 411 | the `-Wall` and `-Werror` GHC options. Might not want to do this all the 412 | time, but excellent for catching unused code and (potential) bugs. (Also see 413 | [this great 414 | article](https://lexi-lambda.github.io/blog/2018/02/10/an-opinionated-guide-to-haskell-in-2018/#warning-flags-for-a-safe-build) 415 | for more info on good warning flags to enable. (Though [as of 416 | 2022](https://github.com/commercialhaskell/stack-templates/commit/f87a30e61536ca604fafe115665e93f1bbbc734f), 417 | the default project you get via `stack new` already contains the recommended 418 | flags. Nice!)) 419 | 420 | And a special mention for 421 | [ormolu](https://hackage.haskell.org/package/ormolu), the zero-config code 422 | formatter. I also use this via the Haskell language server (it's the default 423 | choice for formatting), but it's easy to use as a standalone tool as well. As 424 | a beginner, I don't have strong (Haskell-specific) code formatting opinions, 425 | but I like the ormolu philosophy and, more than that, I like that it Just 426 | Works. (There are a million other formatters too. Choose one and use it 427 | consistently, is the main thing.) 428 | 429 | 430 | ## Pattern matching 431 | 432 | There are a few different pattern matching ideas in Haskell, and they tend to 433 | be a little confused in the explanations I've read so far. Additionally, I've 434 | never been clear which construct is preferred in which case. This section is 435 | my attempt to sort that out. 436 | 437 | ### Function argument pattern matching and `case` statements 438 | 439 | The "lowest level" structure is the `case` statement. These can be used 440 | anywhere, not just in function definitions. For example, these two bits of 441 | code are equivalent: 442 | 443 | ```haskell 444 | -- "Normal" function arg pattern matching: 445 | head' :: [a] -> a 446 | head' [] = error "No head for empty lists!" 447 | head' (x:_) = x 448 | ``` 449 | 450 | ```haskell 451 | -- case statement 452 | head' :: [a] -> a 453 | head' xs = case xs of [] -> error "No head for empty lists!" 454 | (x:_) -> x 455 | ``` 456 | 457 | ...and in fact, function arg pattern matching is just syntactic sugar for 458 | `case` statements, at least according to *LYAH*. In this case, pattern 459 | matching is more readable and (probably) generally preferred. 460 | 461 | ### Guards 462 | 463 | The third idea -- more of a related concept than a separate "thing" -- is to 464 | use guards. See this example from *LYAH*: 465 | 466 | ```haskell 467 | bmiTell :: (RealFloat a) => a -> String 468 | bmiTell bmi 469 | | bmi <= 18.5 = "You're underweight, you emo, you!" 470 | | bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!" 471 | | bmi <= 30.0 = "You're fat! Lose some weight, fatty!" 472 | | otherwise = "You're a whale, congratulations!" 473 | ``` 474 | 475 | "Guards are simply *constraints* for patterns..." is a great way to think 476 | about it. They can be used in both function definitions and `case` 477 | expressions: 478 | 479 | > There are two places guards are allowed: function definitions and case 480 | > expressions. In both contexts, guards appear after a pattern and before the 481 | > body, so you use = in functions and -> in case branches, as usual. 482 | 483 | From https://stackoverflow.com/a/40836465. 484 | 485 | Note that you can use a combo approach: "normal" pattern matching as well as 486 | guards. 487 | 488 | > It's also worth mentioning that since pattern guards were added to Haskell 489 | > 2010, you're allowed to mix patterns and guards like so: 490 | 491 | ```haskell 492 | accumulate_list' :: (Eq a, Num a) => [a] -> ( a -> a -> a ) -> a 493 | accumulate_list' l f 494 | | [] <- l = 0 --pattern for the empty list case 495 | | 10 < 5 = 10 --arbitrary regular guard just because 496 | | (x:xs) <- l = undefined --pattern for the non-empty case 497 | ``` 498 | 499 | From: https://stackoverflow.com/a/25493823. I find this pretty difficult to 500 | read, personally. (Or maybe this is just a bad example?) In either case, just 501 | noting it here for reference. 502 | 503 | ### Pattern matching vs guards 504 | 505 | This SO post sums up some best-practices about when to use which construct: 506 | https://stackoverflow.com/a/4156831. Some of the most useful general 507 | recommendations: 508 | 509 | > * In general, when in doubt, just stick with pattern matching by default, it's 510 | > usually nicer. If a pattern starts getting really ugly or convoluted, then 511 | > stop to consider how else you could write it. Besides using guards, other 512 | > options include extracting subexpressions as separate functions or putting 513 | > case expressions inside the function body in order to push some of the 514 | > pattern matching down onto them and out of the main definition. 515 | > * Definitely don't use guards for things that could be trivially checked with 516 | > a pattern. Checking for empty lists is the classic example, use a pattern 517 | > match for that. 518 | > * Definitely use guards when you need to make a choice based on some property 519 | > that doesn't correspond neatly to a pattern, e.g. comparing two Int values 520 | > to see which is larger. 521 | 522 | ### Pattern matching references 523 | 524 | * http://learnyouahaskell.com/syntax-in-functions 525 | * https://stackoverflow.com/a/2225811 526 | * https://www.haskell.org/tutorial/patterns.html 527 | * Lesson 17.2.2 in *Get Programming with Haskell*, specifically about guards 528 | 529 | 530 | ## Monad stuff 531 | 532 | First off, "Typeclassopedia" is really good, if a bit dense at times, and also 533 | contains SO MANY good links to papers, articles, blog posts, etc: 534 | 535 | https://wiki.haskell.org/Typeclassopedia 536 | 537 | Many of my notes here are sourced from there. 538 | 539 | What's a monad? There are a million explanations for this. *Get Programming 540 | with Haskell* does a good job, I think. Typeclassopedia has links to others. 541 | In particular, this simple demonstration does a pretty good job via a 542 | "trivial" monad (essentially `Identity`): 543 | 544 | http://blog.sigfpe.com/2007/04/trivial-monad.html 545 | 546 | It sums things up thusly, which is not a bad way to *start* thinking about it: 547 | 548 | > So the last question is this: why would you ever wrap data like this? In 549 | > practice people tend not to use the trivial monad very much. Nonetheless, 550 | > you can see how it might be used to represent tainted data. Wrapped data is 551 | > considered tainted. Our API never lets us forget when data is tainted and 552 | > yet it still allows us to do what we like with it. 553 | 554 | To go back to the source, so to speak, scroll down to the bottom of the 555 | following page for some crazy (but supposedly readable?) papers introducing 556 | the subject: 557 | 558 | https://homepages.inf.ed.ac.uk/wadler/topics/monads.html 559 | 560 | And of course, some *LYAH* explanations, which are always fun: 561 | 562 | http://learnyouahaskell.com/for-a-few-monads-more 563 | 564 | ...and the haskell.org "All About Monads" page, which has... a lot: 565 | 566 | https://wiki.haskell.org/All_About_Monads 567 | 568 | ### Some useful monads 569 | 570 | * `Maybe`: obviously! 571 | * `Either`: errors! 572 | * `IO`: special magic monad which (I think?) can only be unwrapped by `main` 573 | * [`Reader`](https://hackage.haskell.org/package/mtl-2.3/docs/Control-Monad-Reader.html): 574 | used to pass around read-only "environment" to functions. ([This 575 | article](https://fsharpforfunandprofit.com/posts/dependencies-3/) is about 576 | F#'s Reader, but is still what made the concept "click" for me.) 577 | * [`Writer`](https://hackage.haskell.org/package/mtl-2.3/docs/Control-Monad-Writer-Lazy.html): basically used for logging, or similar operations 578 | * [`State`](https://hackage.haskell.org/package/mtl-2.3/docs/Control-Monad-State-Lazy.html): used to pass around/isolate mutable state (read/write) 579 | 580 | ### Monad transformers 581 | 582 | Different monads don't compose nicely. You can *nest* them (for example, an 583 | `IO Maybe a`), which works well at first but gets increasingly unwieldy as you 584 | add more layers. (And even at two layers it can be pretty annoying.) 585 | 586 | That's where *monad transformers* come in. Transformers let you nest (or 587 | "stack") a pile of monads together, and treat that whole composite thing 588 | *itself* as a single monad. It sounds complicated and scary, but in practice 589 | it's actually (surprisingly!) straightforward, clean, and easy. 590 | 591 | The type class for monad transformers sums them up pretty well, I think: 592 | 593 | ```haskell 594 | class MonadTrans t where 595 | lift :: Monad m => m a -> t m a 596 | ``` 597 | 598 | They're just wrappers! That's it. 599 | 600 | #### Using monad transformers 601 | 602 | Generally speaking, you rarely (if ever) have to define your own 603 | implementations for these. All the standard monads have them defined already: 604 | `Maybe`, `Reader`, `Either`, etc. Usually just the name with a `T` at the end 605 | (`ReaderT`, e.g.). (`ExceptT` is a notable exception to this rule. No pun, 606 | &c.) 607 | 608 | So basically, you can just stick 'em together. For example, if you have a 609 | function that might fail (`Either`), which depends on some read-only 610 | environment (`Reader`), and which does some I/O (`IO`), you can use `ReaderT` 611 | and `ExceptT` monad transformers to create a composite. (Around the "core" of 612 | the `IO` monad. More on this below.) 613 | 614 | *How* do you stick 'em together? One way would be just to use a `type` alias, 615 | e.g.: 616 | 617 | ```haskell 618 | type TripleMonad a = MaybeT (ReaderT Env IO) a 619 | ``` 620 | 621 | But more commonly you'll see folks hide away the messy details behind a 622 | `newtype`, something closer to this: 623 | 624 | ```haskell 625 | newtype MyApp a = MyA { 626 | runA :: ReaderT AppConfig (StateT AppState IO) a 627 | } deriving (Monad, MonadIO, MonadReader AppConfig, MonadState AppState) 628 | ``` 629 | 630 | Then, e.g. within a `do` block, you can interact with that type (`TripleMonad` 631 | or `MyApp`, in these cases) as a *single unit* and it all pretty much works 632 | how you'd expect. (With the caveat of having to "lift" certain functions to 633 | the correct layer of the stack, which we'll get into in the "Lifting" section 634 | below.) 635 | 636 | #### Order of composition 637 | 638 | **IMPORTANT NOTE:** Order matters in monad composition. The "core" (inner) 639 | monads come first, and they work their way out. So if your `ExceptT` comes 640 | before (i.e. further "inside" than) your `StateT`, that state effectively 641 | won't exist if the `ExceptT` comes back as a `Left`. A little confusing, but 642 | important to wrap your head around: 643 | 644 | > Intuitively, the monads become "more fundamental" the further inside the 645 | > stack you get, and the effects of inner monads "have precedence" over the 646 | > effects of outer ones. 647 | 648 | (From 649 | [Typeclassopedia](https://wiki.haskell.org/Typeclassopedia#Standard_monad_transformers).) 650 | 651 | Technically, *any* monad can be the innermost core of your ball of 652 | transformers. But practically speaking, the core is usually an `IO`. And 653 | importantly, `IO` *must* be the core if it exists in your stack at all (as it 654 | can only be unwrapped by `main`). 655 | 656 | You'll sometimes also see `Identity` used as the core in its place. (Mostly in 657 | monad transformer tutorials, because it's simple.) But this can also be a 658 | handy way to turn a monad *transformer* into a "regular" monad. For example, 659 | some folks find the error-handling mechanics of `ExceptT` better than a plain 660 | `Either`, so will define a type alias for `ExceptT Identity` and use that 661 | instead of `Either`. Or in real life, too -- the `State` monad for example, is 662 | simply [defined 663 | as](https://hackage.haskell.org/package/transformers-0.6.0.4/docs/src/Control.Monad.Trans.State.Lazy.html#State): 664 | 665 | ```haskell 666 | type State s = StateT s Identity 667 | ``` 668 | 669 | #### Lifting 670 | 671 | You'll do a lot of `lift`ing when working with monad transformers. `lift` 672 | simply pulls one of the "inner" types a single layer up toward the "final" 673 | wrapped type. (You'll often see things like `lift . lift`, e.g., to bring a 674 | value "up" two layers.) 675 | 676 | There's also a specific `liftIO` function. This will lift an `IO` value *all* 677 | the way up the stack in a single go. Very handy. 678 | 679 | At first all this type juggling is confusing, but the patterns start to clear 680 | up once you've worked with them a little. And you'll find it actually *cleans 681 | up* your code quite a bit. ([Real World 682 | Haskell](https://book.realworldhaskell.org/read/monad-transformers.html) 683 | wisely recommends wrapping your `lift`s in functions for readability and ease 684 | of refactoring.) 685 | 686 | However, there's an *even easier way* to use monad transformers, one that's 687 | less brittle and doesn't depend on a specific ordering of transformers. We'll 688 | get into that when we talk about `mtl` below. 689 | 690 | #### Monad transformer libraries 691 | 692 | Once you've got the concept down, you'll want to actually *use* the things. 693 | Yet another can o' worms! Most of the info I found was 10+ years old, and a 694 | lot has changed since then. 695 | 696 | [This SO post](https://stackoverflow.com/q/2769487) starts with a valid 697 | question: "which of the 9+ monad transformer libraries should I use?" (The 698 | accepted answer is already quite out of date, but there's some good context in 699 | there if you're curious how things *used* to be.) 700 | 701 | The TL;DR (as I understand it, as of Feb 2024) is: 702 | 703 | - There are two main libraries: 704 | [`transformers`](https://hackage.haskell.org/package/transformers) and 705 | [`mtl`](https://hackage.haskell.org/package/mtl). 706 | - `transformers` provides the *concrete* monad transformer types (stuff like 707 | `ReaderT`, `MaybeT`, etc.). 708 | - `mtl` depends on `transformers`, and extends it to add some "extra stuff". 709 | Namely, type classes, which I'll talk more about below. 710 | - The two libraries used to be at odds, somewhat, so you'll find a lot of 711 | **outdated** information talking about one "versus" the other. (And all the 712 | other now-defunct monad transformer libs.) **You can ignore all this 713 | stuff**, unless you're curious about historical context. 714 | 715 | So to tie things back together: everything we've talked about in the previous 716 | monad transformer sections is contained in the `transfomers` library. However, 717 | the "extra stuff" provided by `mtl` can make them even easier to work with. 718 | 719 | We'll talk about `mtl` more next! 720 | 721 | #### mtl and transformer type classes 722 | 723 | The `mtl` library provides *type classes* for monad transformers. Why does 724 | this matter to us? Well, if you're coming from the OOP world, think of it this 725 | way: why is it better to depend on an *interface* rather than a concrete 726 | class? It's pretty much the same thing here: loose coupling, more flexibility, 727 | easier refactoring, depending only on the behaviors that you need. Etc. 728 | 729 | And practically speaking: a lot less `lift`ing! 730 | 731 | To quote [Monday Morning Haskell](https://mmhaskell.com/monads/transformers#typeclasses): 732 | 733 | > ...there are some typeclasses which allow you to make certain assumptions 734 | > about the monad stack below. For instance, you often don't care what the 735 | > exact stack is, but you just need `IO` to exist somewhere on the stack. This 736 | > is the purpose of the `MonadIO` typeclass.... 737 | > 738 | > We can use this behavior to get a function to print even when we don't know 739 | > its exact monad: 740 | 741 | ```haskell 742 | debugFunc :: (MonadIO m) => String -> m () 743 | debugFunc input = liftIO $ putStrLn ("Successfully produced input: " ++ input) 744 | ``` 745 | 746 | Thanks to the `MonadIO` type class (provided by the `mtl` lib), the above 747 | function would work with *any* of the concrete monad transformer types we 748 | defined above. Or with *any other concrete transformer stack* that contains 749 | `IO`. (Which is pretty much all of them.) 750 | 751 | This level of abstraction lets you add or remove layers from your transformer 752 | stack without having to change *anything* in related functions. 753 | 754 | And of course you can mix and match: 755 | 756 | ```haskell 757 | readLatestLogFile :: (MonadIO m, MonadError Error m) => m [RenameOp] 758 | ``` 759 | 760 | The above function depends on having something `IO`-like and `Either`-like. 761 | But beyond that, it doesn't care about the concrete monad type. Cool! 762 | 763 | The only downside to this style that I've found is that your function 764 | signatures can get a little unwieldy if you're sticking together too many of 765 | these behaviors. (But that might be a sign you need to break things up a bit 766 | anyway.) 767 | 768 | #### Monad transformer resources 769 | 770 | Good intro resources I've found on general monad transformer *concepts*: 771 | 772 | * [This wikibook 773 | chapter](https://en.wikibooks.org/wiki/Haskell/Monad_transformers) is 774 | awesome, finally cemented my understanding. I think. (Deriving your own 775 | `MaybeT` was key.) 776 | * ["Monad Transformers Step by 777 | Step"](https://github.com/mgrabmueller/TransformersStepByStep/blob/master/Transformers.lhs), 778 | a really good paper that walks you through the concepts. 779 | * [Typeclassopedia's](https://wiki.haskell.org/Typeclassopedia#Monad_transformers) 780 | "Monad Transformers" section is also very good. 781 | * ["Grok Haskell Monad 782 | Transformers"](http://blog.sigfpe.com/2006/05/grok-haskell-monad-transformers.html), 783 | a wee little blog post that also does a good job of explaining things. 784 | * [Real World 785 | Haskell](https://book.realworldhaskell.org/read/monad-transformers.html)'s 786 | chapter on monad transformers is a great read for concepts and *some* 787 | practical stuff, but it's fairly out of date, so beware! 788 | 789 | And some resources more on the practical side, libraries and tips for *using* 790 | transformers: 791 | 792 | * [Monday Morning Haskell](https://mmhaskell.com/monads/transformers)'s post 793 | on monad transformers. 794 | * [FPComplete](https://www.fpcomplete.com/haskell/tutorial/monad-transformers/)'s 795 | giant post on the subject, which of course has a *lot* of info. 796 | * [Refactoring to a monad transformer 797 | stack](https://thoughtbot.com/blog/refactoring-to-a-monad-transformer-stack) 798 | is a more concrete example of how to go about using these things. 799 | * An overview of [what's *wrong* with using 800 | them](https://github.com/haskell-effectful/effectful/blob/master/transformers.md), 801 | from the authors of another effects library, 802 | [effectful](https://github.com/haskell-effectful/effectful). Even if you 803 | plan to continue using transformers, these are good caveats to be aware of. 804 | * [mtl is not a monad transformer 805 | library](https://blog.jle.im/entry/mtl-is-not-a-monad-transformer-library.html), 806 | a good overview of using "mtl-style", ie depending on *type classes* rather 807 | than concrete monad transformers. 808 | 809 | 810 | ## Error handling 811 | 812 | A good, if brief overview of the different types of errors one might think 813 | about handling (or not), and how they're represented in Haskell: 814 | 815 | https://wiki.haskell.org/Handling_errors_in_Haskell 816 | 817 | And a longer article, with some good insight and actually useful examples: 818 | 819 | https://www.stackbuilders.com/blog/errors-and-exceptions-in-haskell/ 820 | 821 | As with any programming language, the trick seems to be distinguishing between 822 | the truly "exceptional" errors/exceptions and the expected ones. The expected 823 | ones should be encoded in your dang type signature (`Either`, etc.) if 824 | possible. 825 | 826 | Related, this article builds the idea of `Either` up from scratch, shows some 827 | interesting example of error-handling cases: 828 | 829 | https://www.schoolofhaskell.com/school/starting-with-haskell/basics-of-haskell/10_Error_Handling 830 | 831 | ### Exceptions 832 | 833 | Haskell does have "normal" exceptions, which can be caught and thrown and so 834 | on. See 835 | [`Control.Exception`](https://hackage.haskell.org/package/base-4.17.0.0/docs/Control-Exception.html). 836 | 837 | However, I don't yet grok how best to use these, if at all. I *think* the idea 838 | is to keep them out of pure code entirely, and only use them when dealing with 839 | `IO`. And related to that, the expectation seems to be that any `IO` value 840 | could fail with an exception. (For example, a file doesn't exist, a connection 841 | fails, etc.) So watch out! 842 | 843 | As far as *catching* exceptions: this SO post has some good info on the 844 | particulars of how and when to use the various exception-catching methods: 845 | https://stackoverflow.com/a/6009807 846 | 847 | ### (Avoid) partial functions 848 | 849 | These will fail hard, bringing your program crashing down. And from what I've 850 | experienced, there will be no stack trace and it will be difficult to track 851 | down exactly where in the stack the error occurred. (See the "Stack traces?" 852 | section below.) 853 | 854 | Examples of partial functions to avoid: 855 | 856 | * `head`, which fails on an empty list 857 | * `last`, same as above 858 | * `!!`, the "access the nth elem of a list" function 859 | * `read`, which parses a value out of a string 860 | * ...and probably many others 861 | 862 | So what do you do instead? See [this 863 | article](https://wiki.haskell.org/Avoiding_partial_functions) from the Haskell 864 | wiki for good examples of alternatives to these functions. (Notably absent 865 | from that list are [`readMaybe` and 866 | `readEither`](https://hackage.haskell.org/package/base-4.17.0.0/docs/Text-Read.html#v:readMaybe), 867 | which are safe alternatives to `read`.) 868 | 869 | For lists specifically, there's a 870 | [`Data.List.Safe`](https://hackage.haskell.org/package/listsafe-0.1.0.1/docs/Data-List-Safe.html) 871 | option as well. But I've found the 872 | [`Data.List.NonEmpty`](https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-List-NonEmpty.html) 873 | type to be even more useful. It's exactly what it sounds like: a list which 874 | must have at least one element. 875 | 876 | And this is only somewhat-related, but there's the whole universe of "lens" to 877 | explore, which is likely overkill if you just need to grab an element from a 878 | list (but does also work for that). Plenty of useful stuff: 879 | 880 | https://hackage.haskell.org/package/lens 881 | 882 | The authors even include a wee bit of code you can use to create your own 883 | lenses for arbitrary types, without adding additional dependencies. Nice! 884 | 885 | ### Stack traces? 886 | 887 | By default, one doesn't seem to get stack traces with Haskell. (Maybe this has 888 | something to do with lazy eval? I don't know.) You'll get a one-line error and 889 | maybe the line number of the initial source of the error (i.e. the unit test 890 | that was running), but nothing more. Not super helpful. 891 | 892 | Apparently there are various compile-time options AND runtime options that can 893 | enable stack traces. From a SO post: 894 | 895 | > You can compile your program with profiling enabled and automatic cost 896 | > centers for better traces: `-prof -fprof-auto` and run it with `+RTS -xc`, 897 | > then you will get the sequence of calls that leads to your error. 898 | 899 | Again, note that there are options for both *compiling* and *running* your 900 | program here to get a stack trace. You need both. 901 | 902 | Or, another option: 903 | 904 | > With GHC 8.0.1 and better, just compile with the `-g` flag. No need for 905 | > profiling or cost centers. 906 | 907 | This enables "DWARF" support. See [this blog 908 | post](https://www.haskell.org/ghc/blog/20200403-dwarf-1.html) for more 909 | information. I don't fully understand the trade-offs here yet. 910 | 911 | Also, some more (general) info here: https://wiki.haskell.org/Debugging. 912 | 913 | Frankly, I'm still not sure what the "right" thing to do is, overall. 914 | Certainly one doesn't want to always have profiling enabled. Right? (My 915 | current approach is to hunt down and destroy any code that *might* throw an 916 | error, which I guess is ideal anyway.) 917 | 918 | 919 | ## Language extensions 920 | 921 | Language extensions seemed totally bananas to me at first. Maybe they still 922 | do, but I'm getting used to it. In short, as I understand it, they're simply 923 | "add-ons" to the official Haskell spec, which tends to be pretty conservative. 924 | (In theory, certain extensions might make it into the next version of the 925 | spec, so it's a kind of proving ground, perhaps?) 926 | 927 | In practice, being able to change the behavior of the language, more or less 928 | ad hoc, *somehow* doesn't cause horrible problems. And there are a handful of 929 | "standard" extensions that you'll see used in almost every project. 930 | 931 | One can enable extensions with a compiler flag, using `LANGUAGE` pragmas at 932 | the top of a given file, or for a whole project in your 933 | `package.yaml`/`.cabal` file. Opinions are mixed about what's the "best" way. 934 | (I've been doing it on a per-project basis. It's just simpler.) 935 | 936 | Here's a sampling of useful extensions I've discovered so far: 937 | 938 | * `OverloadedStrings`: string literals play well with other types, 939 | specifically (for me) `Text`. This is the only extension I've used in 940 | *every* project. 941 | * `DuplicateRecordFields`: allow definition of record types with 942 | identically-named fields. 943 | * `NoImplicitPrelude`: don't use the default Haskell `Prelude`. Sometimes 944 | handy. 945 | * `StrictData`: make fields of data types defined in the current module strict 946 | by default. There are all kinds of trade-offs both ways, but this is a good 947 | thing to know about. 948 | * `DeriveGeneric`: I've barely scraped the surface of this one. 949 | [Here's](https://blog.ocharles.org.uk/posts/2014-12-16-derive-generic.html) 950 | an article that goes into it a bit. Mostly, I've just used this to magically 951 | make my types instances of `FromJSON` and `ToJSON`. 952 | 953 | Note that, **as of GHC 9.2.1**, there's a [`GHC2021` 954 | meta-extension](https://downloads.haskell.org/~ghc/9.2.1/docs/html/users_guide/exts/control.html#extension-GHC2021) 955 | which is enabled by default: 956 | 957 | > GHC blesses a number of extensions, beyond Haskell 2010, to be suitable to 958 | > turned on by default. These extensions are considered to be stable and 959 | > conservative. 960 | > 961 | > `GHC2021` is used by GHC if neither `Haskell98` nor `Haskell2010` is turned 962 | > on explicitly. Since later versions of GHC may use a later `GHC20xx` by 963 | > default, users are advised to declare the language set explicitly with 964 | > `-XGHC2021`. 965 | 966 | Although it *works* to enable `GHC2021` as an extension, it's actually 967 | supposed to be set as a `language` in your `package.yaml` / `.cabal` file. 968 | [This article](https://raehik.github.io/2022/10/07/ghc2021-in-2022.html) 969 | covers `GHC2021` really well, including how to enable it and info about some 970 | other useful extensions that didn't make the cut. 971 | 972 | Some more quality reading on extensions: 973 | 974 | * [The official GHC 975 | docs](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts.html), which 976 | aren't so great for opinionated help but are great for reference. 977 | * [This big-ass guide](https://limperg.de/ghc-extensions/) from 2018, which 978 | groups the extensions into "tracks" and gives some good info. 979 | * [The extension 980 | section](https://lexi-lambda.github.io/blog/2018/02/10/an-opinionated-guide-to-haskell-in-2018/#any-flavor-you-like) 981 | of the "Opinionated Guide to Haskell in 2018", which is a great overview of 982 | the "good"/recommended extensions. (At least as of 2018. Not sure how much 983 | has changed of late.) 984 | 985 | 986 | ## Everyday programming tasks 987 | 988 | All the boring everyday programming stuff you need to do is possible in 989 | Haskell, and not any more difficult than in any other language, at least in my 990 | (limited!) experience. 991 | 992 | In addition to the sections below, check out the [State of the Haskell 993 | ecosystem](https://github.com/Gabriella439/post-rfc/blob/main/sotu.md) 994 | document for a massive overview of how Haskell stacks up in various 995 | programming domains. A really good read, with a ton of useful links. And 996 | similarly, check out [Consider 997 | Haskell](https://gilmi.me/blog/post/2020/04/28/consider-haskell), a blog post 998 | that presents a much more succinct take on Haskell's strengths and everyday 999 | usability. 1000 | 1001 | ### CLI arguments 1002 | 1003 | For the simplest use-cases, you can just 1004 | [`getArgs`](https://hackage.haskell.org/package/base-4.17.0.0/docs/System-Environment.html#v:getArgs), 1005 | which gives you back an `IO [String]`. Very easy to use in your `main`. For 1006 | anything more complex than that, you'd likely want to use one of the many 1007 | libraries available. 1008 | 1009 | The unfortunately named 1010 | [optparse-applicative](https://www.stackage.org/package/optparse-applicative#quick-start) 1011 | is probably the most widely-used. At first glance, it looks complicated (and 1012 | it has the word "applicative" in the name), but it was actually super-simple 1013 | to get up and running. The "quick start" (linked above) will get you a long 1014 | way. It can handle pretty much any complex use-case you can throw at it, but 1015 | is also great for simple stuff. 1016 | 1017 | [This blog 1018 | post](https://thoughtbot.com/blog/applicative-options-parsing-in-haskell) was 1019 | also very helpful, and has some good examples of optparse-applicative in 1020 | action. (In particular, it has the clearest example of using sub-commands in a 1021 | CLI app that I was able to find.) 1022 | 1023 | #### A special note on variable-length argument lists 1024 | 1025 | In the 1026 | [Arguments](https://www.stackage.org/package/optparse-applicative#arguments) 1027 | section of the optparse-applicative docs, you'll see a lightning-fast 1028 | explanation of the `some` and `many` combinators. This was not clear to me at 1029 | all from the docs, but: 1030 | 1031 | * `some`: used for *one* or more arguments 1032 | * `many`: used for *zero* or more arguments 1033 | 1034 | Also, a very important note: **do not** use `some` or `many` in conjunction 1035 | with `value` (which sets the default value for an option). If you do, your 1036 | program will simply hang. (The only place I've seen this specifically 1037 | mentioned is in [this 1038 | comment](https://stackoverflow.com/questions/34889516/optparse-applicative-option-with-multiple-values/34894035#comment102633514_34894035) 1039 | on a related S.O. answer. Not sure why this isn't loudly called out in the 1040 | docs.) 1041 | 1042 | #### Other libraries 1043 | 1044 | * [optparse-simple](https://www.stackage.org/package/optparse-simple) is built 1045 | on optparse-applicative, but cuts out some boilerplate for simple use-cases. 1046 | * [cmdargs](https://hackage.haskell.org/package/cmdargs) is also popular and 1047 | supposedly good, but I haven't tried it! 1048 | * [simple-get-opt](https://hackage.haskell.org/package/simple-get-opt) is 1049 | also, well... simple. 1050 | * Check out this 1051 | [meta-list](https://wiki.haskell.org/Command_line_option_parsers) from the 1052 | haskell.org wiki! Good comparison of different options. 1053 | 1054 | ### Unit testing 1055 | 1056 | [HUnit](https://hackage.haskell.org/package/HUnit) exists, but after a short 1057 | trial run I ditched it. HUnit tests can wind up looking like an exaggerated 1058 | parody of unreadable code, e.g.: 1059 | 1060 | ```haskell 1061 | tests = test [ "test1" ~: "(foo 3)" ~: (1,2) ~=? (foo 3), 1062 | "test2" ~: do (x, y) <- partA 3 1063 | assertEqual "for the first result of partA," 5 x 1064 | partB y @? "(partB " ++ show y ++ ") failed" ] 1065 | ``` 1066 | 1067 | After poking around some more, I found [Hspec](https://hspec.github.io/). It 1068 | favors readable tests over terseness and has some other handy features, nicer 1069 | output, and integrates well with HUnit tests if you want to mix/match. 1070 | 1071 | Separately, there's this odd bird called 1072 | [QuickCheck](https://hackage.haskell.org/package/QuickCheck). You can use it 1073 | by itself or with any other test library/framework. It does "random testing of 1074 | program properties". A cool idea, but I haven't used it much yet. 1075 | 1076 | (My intuition here is that you'd have to be careful not to rewrite the logic 1077 | of your system-under-test in order to programmatically test that system. Many 1078 | of the QuickCheck examples I've seen do just that. But still seems handy!) 1079 | 1080 | Other resources: 1081 | 1082 | * [Setting up multiple test suites](https://stackoverflow.com/a/43264723) with 1083 | Stack. For example, unit *and* integration tests. 1084 | * [Tasty](https://hackage.haskell.org/package/tasty), another popular Haskell 1085 | testing framework (which I haven't tried yet). 1086 | * [Using types to unit-test in 1087 | Haskell](https://lexi-lambda.github.io/blog/2016/10/03/using-types-to-unit-test-in-haskell/) 1088 | -- some simple, and then some not-so-simple approaches to drawing "seams" in 1089 | your code for easier testing/mocking. See also [this related 1090 | article](https://lexi-lambda.github.io/blog/2017/06/29/unit-testing-effectful-haskell-with-monad-mock/) 1091 | by the same author, sort of a follow-up. Also includes an overview of their 1092 | `monad-mock` library. 1093 | * [Another article](https://making.pusher.com/unit-testing-io-in-haskell/) 1094 | about unit-testing IO code in Haskell. 1095 | 1096 | ### JSON parsing 1097 | 1098 | Use [Aeson](https://hackage.haskell.org/package/aeson)! (In Greek mythology, 1099 | Aeson is the father of Jason. Get it?) 1100 | 1101 | Some good Aeson resources: 1102 | 1103 | * [This 1104 | cheat sheet](https://williamyaoh.com/posts/2019-10-19-a-cheatsheet-to-json-handling.html) 1105 | succinctly covers just about every use-case you could imagine. 1106 | * [A good introduction](https://www.fpcomplete.com/haskell/library/aeson/) 1107 | from FPComplete. 1108 | * [Another fantastic cheat sheet](https://stackoverflow.com/a/40491001), this 1109 | time about converting among `String`, `Text`, and `ByteString` -- the lazy 1110 | *and* strict varieties. (Aeson uses lazy `ByteString`, so this winds up being 1111 | handy/necessary.) 1112 | * [Easy JSON in Haskell](https://blog.drewolson.org/easy-json), a good lil 1113 | intro to `lens-aeson`. If you have to wrangle some deeply-nested stuff, 1114 | seems like the way to go. 1115 | 1116 | ### Parsing in general 1117 | 1118 | Use [Parsec](https://hackage.haskell.org/package/parsec). Super cool. 1119 | 1120 | * The [`Text.Parsec`](https://hackage.haskell.org/package/parsec-3.1.16.1/docs/Text-Parsec.html) 1121 | package docs are a great place to start. 1122 | * You'll use the [`Text.Parsec.Char`](https://hackage.haskell.org/package/parsec-3.1.16.1/docs/Text-Parsec-Char.html) 1123 | character parsers a lot. 1124 | * [Intro to Parsing with Parsec](http://jakewheat.github.io/intro_to_parsing/) 1125 | was also quite useful. It's packed with examples, and I really like how the 1126 | author shows how to write equivalent parsers in several different styles. 1127 | * [Write Yourself a Scheme](https://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours/Parsing) 1128 | naturally includes a section on parsing. However, it uses the legacy 1129 | `parsec-2` API. Also, its code might not be the best example to follow, 1130 | generally speaking. Still: it never hurts to see more examples! 1131 | 1132 | ### Time and dates 1133 | 1134 | Use the [`time`](https://hackage.haskell.org/package/time-1.9.2) library. The 1135 | [Quick 1136 | Start](https://hackage.haskell.org/package/time-1.9.2/docs/Data-Time.html) 1137 | from its docs is a really useful big-picture overview of the types involved, 1138 | should get you pretty far. 1139 | (TL;DR: The `UTCTime` type is your bread-and-butter.) 1140 | 1141 | Other than the official docs, [this 1142 | article](https://two-wrongs.com/haskell-time-library-tutorial) gives a 1143 | fantastic overview / cheat-sheet of common date-time tasks and how to 1144 | accomplish them. 1145 | 1146 | ### HTTP requests 1147 | 1148 | For simple stuff, (probably?) use 1149 | [Network.HTTP.Simple](https://hackage.haskell.org/package/http-conduit-2.3.8/docs/Network-HTTP-Simple.html). 1150 | For less simple stuff, [wreq](https://hackage.haskell.org/package/wreq)? 1151 | However, wreq uses `lens`, which is a whole other thing to get into. 1152 | 1153 | ### Working with text 1154 | 1155 | It's a little counter-intuitive, but as a general rule: do **not** use 1156 | `String` when working with text in Haskell. The `String` type is simply a 1157 | `List` of characters, and tends to have terrible performance with text 1158 | operations. 1159 | 1160 | Instead, use 1161 | [`Data.Text`](https://hackage.haskell.org/package/text-2.0.1/docs/Data-Text.html) 1162 | (and its related modules, 1163 | [`Data.Text.IO`](https://hackage.haskell.org/package/text-2.0.1/docs/Data-Text-IO.html), 1164 | etc.). Strict by default, performant, easy to use. 1165 | 1166 | It's fine (and convenient!) to use `String` while you're learning, but for 1167 | anything "real", just stick with `Text`. Like, everywhere. 1168 | 1169 | (Note that the 1170 | [`OverloadedStrings`](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/overloaded_strings.html) 1171 | language extension makes this transition pretty painless. It simply makes 1172 | string literals in your code a bit more flexible. Recommended.) 1173 | 1174 | ### Debugging 1175 | 1176 | So far, all of my debugging needs have been met by the venerable 1177 | [`Debug.Trace`](https://hackage.haskell.org/package/base-4.14.0.0/docs/Debug-Trace.html) 1178 | package. It's a continuation of the time-honored tradition known to some as 1179 | "printf debugging". It's simple and effective! 1180 | 1181 | You may be thinking: what about pure functions? Fantastically, it still Just 1182 | Works: 1183 | 1184 | > The `trace` function should only be used for debugging, or for monitoring 1185 | > execution. **The function is not referentially transparent**: its type 1186 | > indicates that it is a pure function but it has the side effect of 1187 | > outputting the trace message. 1188 | 1189 | (Emphasis mine.) 1190 | 1191 | For something more interactive, the [GHCi 1192 | debugger](https://downloads.haskell.org/~ghc/9.4-latest/docs/users_guide/ghci.html#the-ghci-debugger) 1193 | looks pretty cool, but I've yet to try it. 1194 | 1195 | Some related resources: 1196 | 1197 | * [A guide to debugging](https://wiki.haskell.org/Debugging) from the 1198 | haskell.org wiki. 1199 | * A section from the GHCi debugger docs about [debugging 1200 | exceptions](https://downloads.haskell.org/~ghc/9.4-latest/docs/users_guide/ghci.html#debugging-exceptions). 1201 | * Some more [debugging tips and 1202 | tricks](https://haskell.dev/article/Debugging_and_testing_in_Haskell_Tips_and_tricks.html). 1203 | * A [StackOverflow 1204 | post](https://stackoverflow.com/questions/6724434/how-to-debug-haskell-code) 1205 | with a ton of useful resources and advice. (Look at all the answers, not 1206 | just the accepted one.) 1207 | 1208 | ### Concurrency 1209 | 1210 | [Software transactional memory](https://hackage.haskell.org/package/stm) is 1211 | pretty magical. Give it a shot. 1212 | 1213 | * [A good intro to 1214 | STM](https://www.schoolofhaskell.com/school/advanced-haskell/beautiful-concurrency/1-introduction), 1215 | but which also assumes you don't know any Haskell. Still, easy to skim the 1216 | "what's this monad stuff" parts to get to the meat. 1217 | * [An even briefer intro to 1218 | STM](http://computationalthoughts.blogspot.com/2008/03/some-examples-of-software-transactional.html) 1219 | with some decent examples. 1220 | * Be sure to check out the [Single-machine 1221 | Concurrency](https://github.com/Gabriella439/post-rfc/blob/main/sotu.md#single-machine-concurrency) 1222 | section of the "State of the Haskell ecosystem" doc. Great explanation and 1223 | links to plenty of other great resources. 1224 | 1225 | 1226 | ## Miscellaneous good reads 1227 | 1228 | * [An opinionated guide to Haskell in 1229 | 2018](https://lexi-lambda.github.io/blog/2018/02/10/an-opinionated-guide-to-haskell-in-2018/) 1230 | -- really good overview, context, and advice for a beginner from someone who 1231 | clearly has experience in the trenches. Great stuff like: "Warning flags for 1232 | a safe build", "Libraries: a field guide", and a whole big ol' section on 1233 | language extensions. Things have probably changed a bit since 2018, but I 1234 | still found this really valuable. 1235 | * [State of the Haskell ecosystem](https://github.com/Gabriella439/post-rfc/blob/main/sotu.md), 1236 | which I've mentioned a few other times in this document ('cause it's great). 1237 | A really useful way to discover libraries and problem-solving approaches in 1238 | Haskell. Hasn't been updated in a couple years, but I don't know if it needs 1239 | to be. 1240 | * [Three Layer Haskell 1241 | Cake](https://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html) 1242 | -- a good overview of a good approach to designing Haskell applications. See 1243 | also [Invert Your 1244 | Mocks](https://www.parsonsmatt.org/2017/07/27/inverted_mocking.html), a 1245 | semi-related article by the same author about factoring pure code out of 1246 | your impure code (among other things). 1247 | * [The ReaderT Design 1248 | Pattern](https://www.fpcomplete.com/blog/2017/06/readert-design-pattern/), 1249 | also related to above. 1250 | * [An overview of "tagless 1251 | final"](https://www.reddit.com/r/scala/comments/s6ih9p/comment/ht5z2rd/?utm_source=share&utm_medium=web2x&context=3). 1252 | This post is from `r/scala`, but is still applicable/useful for 1253 | understanding the concepts. 1254 | * [Design patterns in 1255 | Haskell](http://blog.ezyang.com/2010/05/design-patterns-in-haskel/): a 1256 | mapping of sorts from the classic "Gang of Four" design patterns into the 1257 | world of functional programming. Surprisingly useful to start shifting one's 1258 | thinking. (Spoiler alert: "first-class functions" is the answer to so many 1259 | problems!) 1260 | * [Writing a game in 1261 | Haskell](https://joevargas.name/blog/2018-02-28-A-Game-in-Haskell.html): a 1262 | great, wonderfully-detailed blog post about building an SDL-based game in 1263 | Haskell. 1264 | * [Module organization guidelines for Haskell 1265 | projects](https://www.haskellforall.com/2021/05/module-organization-guidelines-for.html). 1266 | Some good opinionated best-practices. 1267 | * [A massive SO post](https://stackoverflow.com/a/1016986) about "getting 1268 | started with Haskell" that goes way beyond getting started! 1269 | * [A clear explanation](https://stackoverflow.com/a/384919) about the 1270 | differences between the `foldr`, `foldl`, and `foldl'` functions. 1271 | 1272 | 1273 | ## Document meta 1274 | 1275 | [This document](https://github.com/keithfancher/haskell-notes/blob/master/haskell-notes.md) 1276 | © 2022 by [Keith Fancher](https://github.com/keithfancher) is licensed under 1277 | [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/). 1278 | --------------------------------------------------------------------------------