Dec 22, 2021
Test coverage is a tricky topic. I’m of the opinion that 100% test coverage is not a useful goal. Some take this opinion and discard the idea of tracking coverage altogether. However, there are interesting things you can do with test coverage information in the context of a Pull Request, such as asking if the lines introduced in the Pull Request are covered by tests, or if the Pull Request significantly helps or hurts the overall project coverage.
Sep 10, 2021
This may be obvious or well-known to some, but I discovered the other day that you can make a MonadReader env instance for any MonadState env m trivially. This makes total sense conceptually, since State is just Reader with the extra ability to modify. I’m going to talk it through at length, how it works and why I needed it, but if you’re just interested in copying the code (which I know future me will be), here it is:
May 28, 2021
I love concrete examples that illustrate the day-to-day of the professional Haskell programmer, and show the inspiration for that entirely-untrue quip, “if it compiles, it works”. What is true is some variation of “if it compiles, any logic encoded in the types is correct”. That statement is a tautology (if a program type checks, it means the types are correct), but “encoding logic in the types” isn’t an activity that happens much outside of Haskell.
Mar 23, 2021
Some may say that you shouldn’t write shell beyond a certain, very low bar of complexity. If you reach for arrays, certainly associative arrays (gasp!), or if your script approaches 20, 50, or 100 (how dare you!) lines, maybe you want a “real” language. Everyone’s bar is different, but I’d wager actual options parsing is above it for most. I think this is misguided; parsing options in shell can be valuable enough, and done with low enough complexity, to more than pay for itself on this scale.
Oct 17, 2019
For as long as I’ve built Docker images on CI, I’ve fought the layer caching problem. Working on Haskell projects of many dependencies, an un-cached multi-stage build can take close to an hour. That’s a deal-breaker for deployments, where ten minutes is a reasonable maximum. At some point, Circle quietly released a docker_layer_caching flag in their setup_remote_docker Workflow step, and I happened to get the main Restyled image (restyled/restyled.io) into the beta.
Feb 8, 2019
I maintain an Auth plugin for authenticating with Google OAuth2 in a Yesod application. This plugin has always had functionality overlap with the GoogleEmail2 plugin in the yesod-auth package. Our Google plugin was present, removed (due to said overlap), then returned again, along with some discussion about deprecating GoogleEmail2 in favor of it. What was missing was the documentation for migrating. Things lived happily in this state for some time, until the deprecation of the Google+ API sparked the discussion again.
Dec 16, 2017
The following are all the things I want in place for a Haskell project. This is primarily a copy-paste-able reference for myself, but I’ve also tried to explain or generalize some things to make it useful for anyone first bootstrapping a Haskell project. NOTE: if you were brought here after googling something like “how to Haskell on Circle 2.0”, you’ll just need the Makefile and .circleci/config.yml. 1. Use stack & hpack 🔗.
Dec 17, 2016
In a recent effort to keep my latest laptop more standard and less customized, I’ve been experimenting with XTerm over my usual choice of rxvt-unicode. XTerm is installed with the xorg group, expected by the template ~/.xinitrc, and is the terminal opened by most window managers' default keybindings. The only downside so far has been the inability to select and open URLs via the keyboard. This is trivial to configure in urxvt, but seems impossible in xterm.
Jun 24, 2016
Deleting Git tags that have already been pushed to your remote is something I have to google literally every time I do it; why the invocation is so arcane, I don’t know. Finally, I decided to automate it with a custom sub-command: ~/.local/bin/git-delete-tag #!/bin/sh for tag; do git tag -d "$tag" git push origin :refs/tags/"$tag" done With this script present on $PATH, I can just invoke git delete-tag TAG, .... This is great, but I soon noticed that typing git dele<tab> wouldn’t complete this command (or any custom sub-commands for that matter).
Apr 16, 2016
A while back, I launched a side project called tee-io. It’s sort of like a live pastebin. You use its API to create a command and then send it buffered output, usually a line at a time. Creating the command gives you a URL where you can watch the output come in in real time. We use it at work to monitor the commands run by our bot instead of waiting for the (potentially long) command to finish and report all the output back to us at once.