# Supercede's House Style for Haskell

**URL:** <https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297>\
**Category:** Links\
**Created:** [January 28, 2025, 5:12pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297 "2025-01-28T17:12:51Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![jgt](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jgt/32/3805_2.png) [@jgt](https://discourse.haskell.org/u/jgt)\
**Post date:** [January 28, 2025, 5:12pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/1 "2025-01-28T17:12:51Z")

</div>

> **[Supercede's House Style for Haskell](https://jezenthomas.com/2025/01/style-guide/)**
>
> The house style that has emerged for all Haskell code written at Supercede.

Here’s a style guide I wrote recently which is partly my opinion, and partly observations on what has organically emerged as the way we typically write Haskell code on our team. It describes syntax, but goes beyond that because style encompasses all parts of our work.

What do you think?

---

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [January 28, 2025, 6:33pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/2 "2025-01-28T18:33:28Z")

</div>

I like to put my “block opening” keywords\* at the end of a line. In particular, I write `where` like this:

```haskell
hangingIndent :: MonadIO m => a -> m b
hangingIndent a = fromAToB a where
  fromAToB = do
    someEffect
    someOtherEffectForNoReason
    thisCodeLooksABitWeird

```

\* `let`, `of`, `where`, `do`

---

<div class="post-metadata">

**Author:** ![LaurentRDC](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/laurentrdc/32/4950_2.png) [@LaurentRDC](https://discourse.haskell.org/u/LaurentRDC)\
**Post date:** [January 28, 2025, 7:24pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/3 "2025-01-28T19:24:13Z")

</div>

I both wholeheartedly agree, and swear to never do this at work.

On the whole, I agree that manually controlling the layout of code can help with readability. It’s not necessarily about aesthetics, but rather with organizing information. Just like a good module hierarchy is important for code navigation (among other things), code layout helps visual navigation. I personally like the style presented in the blog post, and would enjoy reading source code in this layout.

But unfortunately, people’s view of a good layout is quite personal. In a work setting, I always highly recommend a _non-configurable_ code formatter (ormolu for Haskell and black for Python, for example). The goal is to maximize global readability by homogeneizing code written by different people, in contrast to maximizing layout on a per-person basis for local readibility.

In a workplace with a mandatory style, isn’t it basically like having a code formatter, but with the extra steps of having to enforce some rules manually?

---

<div class="post-metadata">

**Author:** ![chrisdone](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/chrisdone/32/1408_2.png) [@chrisdone](https://discourse.haskell.org/u/chrisdone)\
**Post date:** [January 28, 2025, 9:38pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/4 "2025-01-28T21:38:55Z")

</div>

The first half prescribing how to layout code is something I’ve always considered a problem to automate away.\[1\]

I do think some of the other sections are valuable and can be justified with practical reasoning:

- Avoiding wildcards because it can ensure you handle new cases.
- Tests should be self contained and meta code vs object code should be clearly distinguished.

They have a flavour of more systems thinking.

Another pattern I’ve observed:

- Keep functions seated in monads on the lowest practical layer of the stack, for better composition and performance e.g.
  - The Query monad (eg Rel8) can be composed into one big query which requires only one round trip to non-local DBs (PG, etc.).
  - A Transaction (eg Hasql) monad obviously composes into a transaction which has atomicity guarantees, but clearly doesn’t compose in the same way as Query.
  - And then a possible Model monad which access DBs, files, HTTP APIs, etc can be called from many contexts (a web handler, a task scheduler, command line, test suite, etc.).
  - Implement Auth on whatever layer needed.
  - Instead, you often see all code in one big App type, and N+1 query problems everywhere, with a web redirect in the middle of a data accessing pattern, dirty DB reads, etc. and it’s very difficult to undo later on.

Haskell makes it easy to cheaply model this in the types, and I think it’s worth doing. It can make code more atomic, perform better, and be more testable. But it’s harder to automate, you have to remember to do it, as a team. (Or perhaps LLMs can help…)

* * *

1. See [this paragraph about my work on autoformatters](https://chrisdone.com/posts/projects/#hindent).

---

<div class="post-metadata">

**Author:** ![rhendric](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/rhendric/32/2689_2.png) [@rhendric](https://discourse.haskell.org/u/rhendric)\
**Post date:** [January 28, 2025, 10:37pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/5 "2025-01-28T22:37:25Z")

</div>

This style choice is fairly pervasive and I don’t understand why:

```haskell
doTheThing ::
     MonadIO m
  => MonadLogger m
  => UserId -- ^ The currently logged in user
  -> CompanyId -- ^ The company the user wishes to foo bar baz
  -> SqlPersistT m ()

```

Some of those types are arguments, some are constraints, and one is the return type. At a glance, which is which? Which one looks special? (`MonadIO m`, because it has no arrow ahead of it.) Where does the kind of the types look like it changes? (`CompanyId` is the first type to have a `->` arrow on its line.) But the special type here is `SqlPersistT m ()`, because it’s the only thing in this signature that is an output. And the first argument type is not `CompanyId` but `UserId`.

I like to format multiline signatures like this, therefore:

```haskell
doTheThing ::
  MonadIO m =>
  MonadLogger m =>
  UserId -> -- The currently logged in user
  CompanyId -> -- The company the user wishes to foo bar baz
    SqlPersistT m ()

```

Am I a monster? Why is this not the convention? (Aside from circular ‘because the tooling doesn’t support it’ reasons, I mean.)

---

<div class="post-metadata">

**Author:** ![Bodigrim](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/bodigrim/32/1457_2.png) [@Bodigrim](https://discourse.haskell.org/u/Bodigrim)\
**Post date:** [January 29, 2025, 12:03am UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/6 "2025-01-29T00:03:43Z")

</div>

> [@rhendric](#):
>
> Am I a monster? Why is this not the convention?

Isn’t it what `ormolu` [does](https://github.com/tweag/ormolu/commit/8466d6e74376f298e05a19b427790fa37e8c39af)?

---

<div class="post-metadata">

**Author:** ![rhendric](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/rhendric/32/2689_2.png) [@rhendric](https://discourse.haskell.org/u/rhendric)\
**Post date:** [January 29, 2025, 12:10am UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/7 "2025-01-29T00:10:42Z")

</div>

Not being an `ormolu` user, I didn’t know that!

From the code I’ve seen on Hackage, it still seems like a minority preference—though I’m happy to see that it’s not quite as small a minority as I feared!

And I still prefer marking the return type with a double-indent over what `ormolu` did at the time of that commit (maybe they’ve adopted that convention also since then).

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [January 29, 2025, 7:41am UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/8 "2025-01-29T07:41:47Z")

</div>

> [@rhendric](#):
>
> Which one looks special?

I agree. It was a revelation to me when `ormolu` chose to put the arrows _after_ arguments. I found it weird at first but now it makes a lot of sense to me.

> [@rhendric](#):
>
> I like to format multiline signatures like this, therefore:
> 
> ```haskell
> doTheThing ::
> MonadIO m =>
> MonadLogger m =>
> UserId -> -- The currently logged in user
> CompanyId -> -- The company the user wishes to foo bar baz
> SqlPersistT m ()
> 
> ```
> 
> Am I a monster? Why is this not the convention?

As @bodigrim says, that’s the `ormolu` style, apart from the final indent. I guess I could get used to your way, but `ormolu` suits me fine for now.

> [@chrisdone](#):
>
> meta code vs object code should be clearly distinguished

What are “meta code” and “object code” here?

---

<div class="post-metadata">

**Author:** ![chrisdone](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/chrisdone/32/1408_2.png) [@chrisdone](https://discourse.haskell.org/u/chrisdone)\
**Post date:** [January 29, 2025, 8:15am UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/9 "2025-01-29T08:15:10Z")

</div>

> [@tomjaguarpaw](#):
>
> What are “meta code” and “object code” here?

I was using that as a short-hand; meta as “analysis of something at a higher level” (scaffold, setup/teardown, assertions, fake data, config, …) and object as “a concrete thing within a system” (functions, modules, services, …). AKA the test harness and the system under test.

---

<div class="post-metadata">

**Author:** ![jackdk](https://avatars.discourse-cdn.com/v4/letter/j/9f8e36/32.png) [@jackdk](https://discourse.haskell.org/u/jackdk)\
**Post date:** [January 29, 2025, 12:22pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/10 "2025-01-29T12:22:14Z")

</div>

It is gaining ground. I used to like the old way, but I like being able to grep for definitions with a regex like `^name ::`. Now that linear types have landed, arrows etc are no longer uniformly two characters, which means the neat vertical alignment is not guaranteed.

---

<div class="post-metadata">

**Author:** ![mpilgrem](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mpilgrem/32/2529_2.png) [@mpilgrem](https://discourse.haskell.org/u/mpilgrem)\
**Post date:** [January 29, 2025, 1:23pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/13 "2025-01-29T13:23:57Z")

</div>

I would be interested in views on how to style functions with large numbers of arguments. For example, the Stack project, which respects 80-character lines for the most part, has code formatting like the following for functions that yield an action:

```haskell
-- | Perform the actual plan
executePlan ::
     HasEnvConfig env
  => BuildOptsCLI
  -> BaseConfigOpts
  -> [LocalPackage]
  -> [DumpPackage] 
     -- ^ global packages
  -> [DumpPackage] 
     -- ^ snapshot packages
  -> [DumpPackage] 
     -- ^ project packages and local extra-deps
  -> InstalledMap
  -> Map PackageName Target
  -> Plan
  -> RIO env ()
executePlan
    boptsCli
    baseConfigOpts
    locals
    globalPackages
    snapshotPackages
    localPackages
    installedMap
    targets
    plan
  = do
    logDebug "Executing the build plan"
    bopts <- view buildOptsL
    withExecuteEnv
      bopts
      boptsCli
      baseConfigOpts
      locals
      globalPackages
      snapshotPackages
      localPackages
      mlargestPackageName
      (executePlan' installedMap targets plan)

    ...

```

Are there ‘better’ ways?

---

<div class="post-metadata">

**Author:** ![mpilgrem](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mpilgrem/32/2529_2.png) [@mpilgrem](https://discourse.haskell.org/u/mpilgrem)\
**Post date:** [January 29, 2025, 1:53pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/15 "2025-01-29T13:53:22Z")

</div>

One argument in favour of short lines in code (e.g. 80 characters or less) is that it makes the code much easier to read on an iPhone with the GitHub app.

---

<div class="post-metadata">

**Author:** ![mpilgrem](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mpilgrem/32/2529_2.png) [@mpilgrem](https://discourse.haskell.org/u/mpilgrem)\
**Post date:** [January 29, 2025, 2:14pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/17 "2025-01-29T14:14:41Z")

</div>

Another argument in favour of keeping the `::` on the same line as the function name is that it is syntax highlighter-friendly (when it comes to colouring the function name).

---

<div class="post-metadata">

**Author:** ![simonmic](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/simonmic/32/1796_2.png) [@simonmic](https://discourse.haskell.org/u/simonmic)\
**Post date:** [January 29, 2025, 9:52pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/18 "2025-01-29T21:52:15Z")

</div>

The original post is great, thanks.

I don’t use a code formatter, but I’m onboard with it being a good idea sooner or later.

But I always strongly favour breaking the 80 char limit and using longer lines when needed (within reason), with line wrapping usually turned off (ie, with too-long lines truncated). Because seeing clear code structure, and more of it, is much more valuable than fitting in narrow horizontal space. I usually don’t need to be seeing the end of every line, instead I want to see more of the program. When I do want to see line ends, it’s easy to temporarily maximize a window, toggle line wrap, or scroll.

---

<div class="post-metadata">

**Author:** ![amesgen](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/amesgen/32/2083_2.png) [@amesgen](https://discourse.haskell.org/u/amesgen)\
**Post date:** [January 29, 2025, 10:06pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/19 "2025-01-29T22:06:36Z")

</div>

> [@maxigit](#):
>
> I don’t think Haddock would understand
> 
> ```haskell
> CompanyId --> -- ^ The company the user wishes to foo bar baz
> 
> ```
> 
> (Correct me if I am wrong).

Haddock indeed didn’t understand this in the past (up until GHC 8.10, it would even fail to parse it back then), but since GHC 9.0, Haddock can parse it just fine and _does_ consider the comment here to apply to `CompanyId`.

---

<div class="post-metadata">

**Author:** ![jackdk](https://avatars.discourse-cdn.com/v4/letter/j/9f8e36/32.png) [@jackdk](https://discourse.haskell.org/u/jackdk)\
**Post date:** [January 29, 2025, 11:06pm UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/20 "2025-01-29T23:06:22Z")

</div>

> [@maxigit](#):
>
> `CompanyId --> -- The company the user wishes to foo bar baz`

Ormolu (which I use but sometimes find rather frustrating) deals with this by using `-- |` comments:

```haskell
foo ::
  -- | The company the user wishes to foo bar baz
  CompanyId ->
  Whatever

```

---

<div class="post-metadata">

**Author:** ![vshabanov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/vshabanov/32/2080_2.png) [@vshabanov](https://discourse.haskell.org/u/vshabanov)\
**Post date:** [January 30, 2025, 12:31am UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/21 "2025-01-30T00:31:25Z")

</div>

It’s pretty good.

The space before `MonadIO` and several `=>` look unusual in

```haskell
doTheThing ::
     MonadIO m
  => MonadLogger m
  => UserId -- ^ The currently logged in user
  -> CompanyId -- ^ The company the user wishes to foo bar baz
  -> SqlPersistT m ()
doTheThing userId companyId = _

```

I would use a more uniform

```haskell
doTheThing 
  :: (MonadIO m, MonadLogger m)
  => UserId -- ^ The currently logged in user
  -> CompanyId -- ^ The company the user wishes to foo bar baz
  -> SqlPersistT m ()
doTheThing userId companyId = _

```

For records I prefer to put the constructor on the new line:

```haskell
data User
  = User
    { userName :: UserName
    , userEmail :: Email
    , userDateOfBirth :: Day
    }
{- so it will look uniform if we add
  | AnotherConstructor
    { foo :: Foo
    , ...
    }
-}

```

I’m not a fan of automatic formatting. I think people can express their intent better than any formatter. Unless there is something very irritating (like random spaces and identation), I can tolerate almost any Haskell formatting.

The most important thing is how clean the ideas behind the code are. I’ve seen a lot of nicely formatted spaghetti, and worked with a guy who uses tabs like [this](https://github.com/thesz/hhdl/blob/master/src/Hardware/HHDL/HHDL.hs). I’d prefer tabs.

Surprisingly, books that have nothing to do with FP are still helpful in developing a good style of thinking. I would recommend “A Philosophy of Software Design” by Ousterhout, “Pragmatic Programmer”, “The Art of Doing Science and Engineering”, and “The Art of Unix Programming”.

Closer to Haskell I would recommend to use as much pure code as possible and spend time thinking on the task at hand instead of creating overengineered “frameworks”. Yes, it’s easier and more fun to create the 1001st effects system (and you can always do it at home), but it’s no fun to maintain it.

---

<div class="post-metadata">

**Author:** ![darkxero](https://avatars.discourse-cdn.com/v4/letter/d/f07891/32.png) [@darkxero](https://discourse.haskell.org/u/darkxero)\
**Post date:** [January 30, 2025, 1:50am UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/22 "2025-01-30T01:50:45Z")

</div>

Wouldn’t

```haskell
Design for qualified imports. If you have module called Email,
it should probably expose a function called parse so that it
can be imported qualified and called with Email.parse,
rather than the clumsy Email.parseEmail.

```

imply

```haskell
data User = User
  { name :: UserName
  , email :: Email
  , dateOfBirth :: Day
  }

```

rather than

```haskell
data User = User
  { userName :: UserName
  , userEmail :: Email
  , userDateOfBirth :: Day
  }

```

?

---

<div class="post-metadata">

**Author:** ![george.fst](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/george.fst/32/4933_2.png) [@george.fst](https://discourse.haskell.org/u/george.fst)\
**Post date:** [January 31, 2025, 12:51am UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/23 "2025-01-31T00:51:36Z")

</div>

I suppose it’s not uncommon to want multiple fields of the same name _within_ a module, especially with something short like `name`. In general, working with unprefixed field names is quite annoying without `NoFieldSelectors`, which has been around for a few years now, but I get the impression\* it hasn’t been that widely used. And to be fair, converting a large pre-existing codebase to that style could be a lot of work for a pretty small payoff.

\* I’d be interested in firm numbers, but [alas](http://discourse.haskell.org/t/2023-state-of-haskell-survey/8213).

---

<div class="post-metadata">

**Author:** ![george.fst](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/george.fst/32/4933_2.png) [@george.fst](https://discourse.haskell.org/u/george.fst)\
**Post date:** [January 31, 2025, 1:05am UTC](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297/24 "2025-01-31T01:05:06Z")

</div>

> All compiler warnings should be upgraded to errors.

Do you mean to say that you enable `-Werror` everywhere, and not just on CI? I’m aware that some people do but I’ve never seen the appeal. I find that running code which temporarily contains some harmless warnings like unused variables or imports is something that I do _constantly_.

[Next page](https://discourse.haskell.org/t/supercedes-house-style-for-haskell/11297.md?page=2)
