13 Oct 2026

QuickCheck: shrinking like tuples, writing like applicative

The QuickCheck documentation for Arbitrary says that

There is no generic arbitrary implementation included because we don't know how to make a high-quality one.

Though in practice I've found that very often it suffices to write one that uses the fact that Gen is an Applicative. For instance, this type

data Foo = Foo
    { tata :: Int
    , titi :: Double
    }

would get an implementation that looks like this

instance Arbitrary Foo where
    arbitrary = Foo <$> arbitrary <*> arbitrary

When it comes to writing the function for shrinking Foo it is possible to rely on a generic function and the documentation says that

The default implementation returns the empty list, so will not try to shrink the value. If your data type has no special invariants, you can enable shrinking by defining shrink = genericShrink, but by customising the behaviour of shrink you can often get simpler counterexamples.

Based on some manual testing it seems that genericShrink generates something like this for the type Foo above

instance Arbitrary Foo where
    shrink (Foo tata_ titi_) = Foo <$> shrink tata_ <*> shrink titi_

which means that if shrink tata_ generates a list of m elements and shrink titi_ generates a list of n elements, then shrink foo will generate a list of m×n elements. It's clear that the size can become problematic with more fields. It also means that it's very easy to get an empty list – if shrink v results in an empty list, then shrink foo is also empty. Oh, and shrink Nothing is []!

A colleague pointed out that tuples have a rather efficient implementation of shrink that grows linearly with the number of elements and doesn't reduce to the empty list as easily. I could use it for Foo like this

instance Arbitrary Foo where
    shrink (Foo tata_ titi_) = uncurry Foo <$> shrink (tata_, titi_)

However, that doesn't scale that well to more fields. Up to a point I can use list comprehensions, but it gets a bit difficult to read, I find. On top of that, the largest tuple with an Arbitrary instance has 10 elements, and then I'll have to either define more or use inner tuples.

Wouldn't it be nice to write shrink in something that looks Applicative, but behaves like tuples?

Here's one approach to this.

First a type to hold information about what's being shrunk, or in this case waned

data Wane a = Wane a [a]
    deriving (Generic, Show)

instance Functor Wane where
    fmap f (Wane a as) = Wane (f a) (f <$> as)

Then a couple of functions to bring values in and out, unWane to get the list of values out and wane to wrap a value in Wane

unWane :: Wane a -> [a]
unWane (Wane _ as) = as

wane :: (Arbitrary a) => a -> Wane a
wane a = Wane a (shrink a)

Finally a way to combine two Wane values is needed, and here I was inspired by the implementation of Arbitrary for (a,b)

infixl 4 \*/

(\*/) ::  Wane (a -> b) -> Wane a -> Wane b
(\*/) (Wane f fs) (Wane a as) =  Wane (f a) ([f a' | a' <- as] <> [f' a| f' <- fs])

It's now possible to write shrink for Foo like this

instance Arbitrary Foo where
    shrink (Foo tata_ titi_) = unWane $ Foo <$> wane tata_ \*/ wane titi_

That scales to more fields just as nicely as applicative style, and the result matches what the variant using tuples produces (same elements, but the order is different).

Tags: haskell quickcheck
13 Oct 2026

Emacs salmagundi, 2026-10-11

Combining lists of compilation commands

To my delight I found that emacs-multi-compile will combine the of all matches compilation commands!

I added this to my setup

(add-to-list 'multi-compile-alist
               '((mes/is-in-git-project) . (("git clean -n" "git clean -ndx" (project-root (project-current)))
                                            ("git clean -f" "git clean -fdx" (project-root (project-current))))))

and those commands are now shown together with the ones I defined for Haskell project (see my previous post) when both match.

Recognising a git project

To add the git commands to multi-compile-list I needed a function to determine if the current buffer is in a git working tree. I failed to find something fitting so I ended up adding this little function.

(defun mes/is-in-git-project ()
  "Check if we're currently in a git project."
  (when-let* ((proj-dir (project-root (project-current))))
    (vc-git-root proj-dir)))

Taming compilation mode buffers

I'm using display-buffer-alist to control how Emacs places buffers. For compilation mode I had the following actions.

(display-buffer-reuse-mode-window display-buffer-in-side-window)
(mode compilation-mode)
(window-height . 0.25)
(side . bottom)
(post-command-select-window . t)

That last command made switching buffers with consult-buffer a bit irritating as previewing would interrupt the buffer switching by selecting the compilation window. However, I really want the compilation window selected after a compilation. Or rather, as I realised after reflecting a bit, I want the compilation window selected if there are errors.

Compilation mode has a way of running functions when a compilation finishes so I defined two functions and added them to compilation-finish-functions.

(defun mes/close-successful-compilation (buf msg)
  "Close compilation buffer after success."
  (when (and (buffer-live-p buf)
             (with-current-buffer buf (eq major-mode 'compilation-mode))
             (string-match "finished" msg))
    (run-with-timer 3 nil
                    (lambda ()
                      (kill-buffer buf)))))

(defun mes/select-failed-compilation (buf msg)
  "Select compilation buffer after failed compilation."
  (when (and (buffer-live-p buf)
             (with-current-buffer buf (eq major-mode 'compilation-mode))
             (string-match "abnormally" msg))
    (select-window (get-buffer-window buf))))

  (add-to-list 'compilation-finish-functions #'mes/close-successful-compilation)
  (add-to-list 'compilation-finish-functions #'mes/select-failed-compilation)

With that a successful compilation is closed automatically after 3s and on a failed compilation the compilation buffer is selection.

Tags: emacs
06 Sep 2026

Emacs salmagundi, 2026-09-06

Compilation commands by project type

I while ago I added a minor mode, haskell-ng-project-mode, to my Haskell mode. The idea I had was that I could use it to add keybindings for running various tools (via compile), e.g. I bound cabal build and cabal test , p b and , p t respectively. Then I hooked in the minor mode in my haskell-ng-mode. Soon I realised it'd be nice to have those shortcuts available in dired too, so I hooked it in there as well. When I later wanted to re-run the tests after modifying a JSON file that was part of a golden test I realised that this wasn't a very nice solution at all.

After looking around a bit I found emacs-multi-compile. I removed the minor mode and add this configuration instead

(add-to-list 'multi-compile-alist
             '((haskell-ng-is-project) . (("cabal build" "cabal build -j --semaphore" (project-root (project-current)))
                                          ("cabal test" "cabal test" (project-root (project-current)))
                                          ("fourmolu" "fourmolu -i $(fd .hs$)" (project-root (project-current))))))

I've had some vague thoughts that it'd be rather easy to write something slightly more custom, but emacs-multi-compile works very well for me so I'm very happy with it.

Jumping between implementation and test, again

I wrote about this a while ago. At the time I came up with a way of bending ff-find-other-file to my will, but soon after that I ran into a case where there may be 2 "other files" – one of the Haskell projects at work put unit tests in files ending in Spec.hs and property tests in filed ending with Prop.hs. Unfortunately this is a situation that ff-find-other-file can't handle.

I ended up hacking together consult-kith to deal with it. The configuration to handle two kinds of test files looks like this

(setq-local consult-kith-alist `((,(rx (seq "Spec.hs" eol)) (".hs"))
                                 (,(rx (seq "Prop.hs" eol)) (".hs"))
                                 (,(rx (seq ".hs" eol)) ("Prop.hs" "Spec.hs")))
            consult-kith-search-directories '("src" "test"))

The project has since settled on only using Spec.hs for tests, but I'm sticking to consult-kith for now.

Tags: emacs
13 Aug 2026

Emacs salmagundi, 2026-08-13

Here's a few minor tweaks I've made to my Emacs setup recently.

Limiting enabled tree-sitter modes

After reading Rahul's post Emacs 31 Is Around the Corner: The Changes I'm Already Daily Driving I simplified my setup and turned on all the tree-sitter modes

(treesit-enabled-modes t)

I regretted that as soon as I opened a YAML file though. It turns out the yaml-ts-mode is rather unusable.1 I switched back to yaml-mode and adjusted the value of treesit-enabled-modes to include what I have use for (the change):

(treesit-enabled-modes '(bash-ts-mode
                         c++-ts-mode
                         c-or-c++-ts-mode
                         c-ts-mode
                         dockerfile-ts-mode
                         go-mod-ts-mode
                         go-ts-mode
                         go-work-ts-mode
                         json-ts-mode
                         python-ts-mode
                         rust-ts-mode
                         typescript-ts-mode))

The customization of treesit-enabled-modes contains a list of all the supported modes.

I hope someone will take pity on yaml-ts-mode and make it usable soon.

Tree-sitter grammar for Cabal files

When I began tinkering with my own treesitter-based mode for Haskell I failed to find a tree-sitter grammar for Cabal files so I wrote a rather rough one myself. My hope was that it could serve as a base, or motivation, for someone else to write a proper one. It took more than 2 years, but now it's finally happened!

I've switched my mode to use Curtis's grammar and I'll be archiving mine. (The change.)

Hello editable xref, good bye wgrep

Rahul's post also mentions that editable xref buffers. I had the same itch to have editable xref buffers, and I'd added a function to turn them into grep buffers to be able to edit them. I've now switched to using the built-in support, and removed the function.

At the same time I also decided to remove wgrep and instead use the builtin function for editing grep buffers.

Footnotes:

1

A mode for an indentation-sensitive language really ought to at least handle indentation!

Tags: emacs haskell
04 May 2026

Jumping to errors in Evil

Recently I realised that it'd be really nice if jumping to errors would store the previous location in the Evil jump list. These definitions do just that

(evil-define-motion mes/evil-goto-next-error (count)
  :jump t
  (unless (bound-and-true-p flymake-mode) (signal 'search-failed nil))
  (flymake-goto-next-error count))
(evil-define-motion mes/evil-goto-prev-error (count)
  :jump t
  (unless (bound-and-true-p flymake-mode) (signal 'search-failed nil))
  (flymake-goto-prev-error count))

and for now I've bound them to C-j and C-k (because that's what evil-collection does)

(general-def flymake-mode-map
  :states 'normal
  "C-j" 'mes/evil-goto-next-error
  "C-k" 'mes/evil-goto-prev-error)

This makes it easier to make a change, fix the errors caused by the change and then return to where I was.

Tags: emacs evil
Other posts