# Maintaining haskell programs

**URL:** <https://discourse.haskell.org/t/maintaining-haskell-programs/7166>\
**Category:** Uncategorized\
**Created:** [August 2, 2023, 4:49am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166 "2023-08-02T04:49:13Z")\
**Posts on this page:** 20\
**Page:** 3

<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:** [August 4, 2023, 2:21pm UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/44 "2023-08-04T14:21:09Z")

</div>

What I mean to say is that I think you can only have two of these three points:

- bleeding edge experimental features
- a guarantee that all your programs will still compile in X years time
- a simple compiler that can be maintained by a low-budget team

Of course all three points have varying gradations, so it might be possible to strike a better balance than we do now.

---

<div class="post-metadata">

**Author:** ![acowley](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/acowley/32/257_2.png) [@acowley](https://discourse.haskell.org/u/acowley)\
**Post date:** [August 4, 2023, 2:34pm UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/45 "2023-08-04T14:34:34Z")

</div>

That’s a great summary!

---

<div class="post-metadata">

**Author:** ![lorenzo](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/lorenzo/32/1294_2.png) [@lorenzo](https://discourse.haskell.org/u/lorenzo)\
**Post date:** [August 4, 2023, 3:20pm UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/46 "2023-08-04T15:20:33Z")

</div>

I cannot think of any breakage in my code because the use of extensions.

On the other hand I can think of one (minor) breakage that involved no extensions: the split of Monoid into two classes. But this was a very trivial change in my code.

---

<div class="post-metadata">

**Author:** ![mouse07410](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mouse07410/32/2399_2.png) [@mouse07410](https://discourse.haskell.org/u/mouse07410)\
**Post date:** [August 4, 2023, 9:11pm UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/48 "2023-08-04T21:11:47Z")

</div>

Respectfully disagree - to me it sounds like “maintainability would be much better if we all stick with GHC-8.10.7 (or older - whatever’s the latest GHC-7) and whatever Cabal/Stack that accompanies it”.

Sure, if toolchains did not change, and existing packages’ API didn’t change - maintaining Haskell apps would be a breeze. Unfortunately, that’s not the case. “And if wishes were wings - . . .”

---

<div class="post-metadata">

**Author:** ![Underlap](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/underlap/32/3910_2.png) [@Underlap](https://discourse.haskell.org/u/Underlap)\
**Post date:** [August 9, 2023, 1:36am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/49 "2023-08-09T01:36:58Z")

</div>

39 years of software development make me think that language extensions are a likely source of maintainability issues. It’s analogous to the maintainability issues for C++ (and other “large” languages) for teams above a certain size. Small teams can decide on, and police, the set of language extensions they use. But this doesn’t work so well in large teams, especially if there is a lot of turnover over time.

---

<div class="post-metadata">

**Author:** ![Ambrose](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/ambrose/32/5672_2.png) [@Ambrose](https://discourse.haskell.org/u/Ambrose)\
**Post date:** [August 9, 2023, 1:59am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/50 "2023-08-09T01:59:07Z")

</div>

What about language extensions does this exactly? As a manager or whatever, I guess I see how it can run afoul of the “engineers are cogs who should be able to get run over by buses” philosophy. But from a technical standpoint, I don’t get how a module being able to turn on LambdaCase, ImplicitParams, LinearTypes, DataKinds, TypeFamilies, etc is gonna be any worse than a project having a messy dependency graph or being untestable (way more common of problems + language agnostic).

---

<div class="post-metadata">

**Author:** ![Underlap](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/underlap/32/3910_2.png) [@Underlap](https://discourse.haskell.org/u/Underlap)\
**Post date:** [August 9, 2023, 5:30am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/51 "2023-08-09T05:30:00Z")

</div>

I agree that messy dependency graphs and untestable code are also likely to make Haskell code unmaintainable, but, as you point out, these are language agnostic. Language extensions, especially if many of them are used inconsistently across a large project, could greatly increase the difficulty of understanding and modifying the code. I suspect that as more and more extensions come into existence, it might even be possible for a large project to become arbitrarily unmaintainable. Lsmor [pointed out](http://discourse.haskell.org/t/maintaining-haskell-programs/7166/5) some specific difficulties.

---

<div class="post-metadata">

**Author:** ![Ambrose](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/ambrose/32/5672_2.png) [@Ambrose](https://discourse.haskell.org/u/Ambrose)\
**Post date:** [August 9, 2023, 8:23am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/52 "2023-08-09T08:23:12Z")

</div>

Maybe it would be helpful to give a concrete example of a program that rotted due to using extensions? Because I’ve never seen a concrete example of a GHC extension actually causing maintenance problems.

When I was new to Haskell, extensions were odd. But is there one (even the most onerous) that is actually some scary problem for a professional software developer? They’re well documented, tightly scoped, and the worst case is the code doesn’t compile in most cases (I guess this is where people tell their RecordWildCard shadowing horror stories 😆)

And like I said, “more cognitive load” isn’t a maintenance problem. One more new concept/syntax/whatever doesn’t constitute a “maintenance problem.” I can easily flip the arrow and call it an attitude problem.

Haskell does have costs due to its (good imo) willingness to bork backwards compat. Avoid (success at all costs) and whatnot. That is the “maintenance problem” in my eyes. And it’s trivial and mechanical to work through.

---

<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:** [August 9, 2023, 8:55am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/53 "2023-08-09T08:55:09Z")

</div>

[Lots of packages](https://github.com/search?q=simplified+subsumption+language%3Ahaskell&type=commits) were broken for a long time on 9.0 (many even skipped 9.0 altogether) due to the [simplified subsumption](https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0287-simplify-subsumption.rst) changes to the `RankNTypes` extension.

---

<div class="post-metadata">

**Author:** ![f-a](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/f-a/32/2740_2.png) [@f-a](https://discourse.haskell.org/u/f-a)\
**Post date:** [August 9, 2023, 9:13am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/54 "2023-08-09T09:13:36Z")

</div>

> [@Ambrose](#):
>
> And like I said, “more cognitive load” isn’t a maintenance problem. One more new concept/syntax/whatever doesn’t constitute a “maintenance problem.” I can easily flip the arrow and call it an attitude problem.

In @Underlap assumption (“for teams above a certain size”), this might well be a problem.

Small teams can develop a cohesive communication strategy and establish a set of shared techniques from which to pick from while developing. The bigger the team (or the more fractured the team), the greater the risk of ending up in a Tower of Babel, where developer from team α has problems understanding the lingo of developer from team β.

Code is written once and read many times; friction is a cost.

---

<div class="post-metadata">

**Author:** ![Probie](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/probie/32/3232_2.png) [@Probie](https://discourse.haskell.org/u/Probie)\
**Post date:** [August 9, 2023, 9:37am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/55 "2023-08-09T09:37:45Z")

</div>

> that is actually some scary problem for a professional software developer

One language extension that terrifies “Probie the software engineer” (but not “Probie the hacker”) is `ImportQualifiedPost`.

---

<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:** [August 9, 2023, 9:52am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/56 "2023-08-09T09:52:31Z")

</div>

Why is that?

* * *

* * *

---

<div class="post-metadata">

**Author:** ![Underlap](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/underlap/32/3910_2.png) [@Underlap](https://discourse.haskell.org/u/Underlap)\
**Post date:** [August 9, 2023, 10:14am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/57 "2023-08-09T10:14:17Z")

</div>

Ok, full disclosure, I’m relatively new to Haskell. I don’t have an example project that’s unmaintainable because of extensions. Hence my guarded language (“likely”, “could”).

But my concerns are backed up by some practical experience. I wanted to contribute to a Haskell project (nameless, to protect the innocent) and the first module I opened up used:

```haskell
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}

```

(other modules used other extensions). I hate guesswork, so I set about reading the docs for the unfamiliar extensions.

[Flexible contexts](https://downloads.haskell.org/~ghc/9.0.1/docs/html/users_guide/exts/flexible_contexts.html) didn’t seem too threatening, except that the docs were for GHC 9.0.1 and the [latest docs](https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/flexible_contexts.html) are much terser (why?). The older docs were in a section that pointed at the paper [Type classes: exploring the design space](http://research.microsoft.com/~simonpj/Papers/type-class-design-space/), which looked like a challenging read in itself.

[Type families](https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/type_families.html) looked harder. The docs linked to three academic papers and then extended over several pages. The [Haskell wiki page on type families](https://wiki.haskell.org/GHC/Type_families) was a little gentler, but still pretty off-putting.

I dare say if I regarded getting up to speed on each of these extensions as a project in its own right, I could eventually become sufficiently confident that I would then know how to work with the module in question.

Perhaps the solution is education and hiring, so that there is a sufficient pool of developers familiar with the most common extensions. But from my perspective as a seasoned programmer, that just feels like another symptom of the potential for unmaintainability.

---

<div class="post-metadata">

**Author:** ![Probie](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/probie/32/3232_2.png) [@Probie](https://discourse.haskell.org/u/Probie)\
**Post date:** [August 9, 2023, 10:24am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/58 "2023-08-09T10:24:05Z")

</div>

`ImportQualifiedPost` creates a decision where neither choice matters, and yet will consume a person hour or more of the team’s time every time there’s a discussion about using it, as well as more time documenting that decision. Ok, so it only costs a few hundred dollars (which might blow out to one or two thousand dollars depending on team dynamics - I’ve been at places where bikeshedding arguments have gotten out of control), but it doesn’t feel like money well spent.

---

<div class="post-metadata">

**Author:** ![arybczak](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/arybczak/32/2527_2.png) [@arybczak](https://discourse.haskell.org/u/arybczak)\
**Post date:** [August 9, 2023, 10:34am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/59 "2023-08-09T10:34:48Z")

</div>

IME `ImportQualifiedPost` is fine. You enable it alongside `-Wprepositive-qualified-module` and you’re back to one choice.

Something like `BlockArguments` is far more problematic because there’s not even an `hlint` check for redundant `$` with it, so you have potential for discussion in each code review.

---

<div class="post-metadata">

**Author:** ![hellwolf](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/hellwolf/32/3020_2.png) [@hellwolf](https://discourse.haskell.org/u/hellwolf)\
**Post date:** [August 9, 2023, 11:36am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/60 "2023-08-09T11:36:51Z")

</div>

What is folks’ opinion on `BlockArguments`? I am using it, but I sense it could be controversial.

---

<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:** [August 9, 2023, 11:42am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/61 "2023-08-09T11:42:48Z")

</div>

If you want to avoid an hour’s discussion on such matters I suggest an opinionated code formatter (at work we use Ormolu, and I’m very happy with it).

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [August 9, 2023, 12:40pm UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/62 "2023-08-09T12:40:01Z")

</div>

As for `BlockArguments` in particular:

```haskell
{-# LANGUAGE BlockArguments #-}
module BlockArgsBedlam where

f :: a -> b -> Char
f _ _ = '?'

mt :: IO ()
mt = putChar '~'

mu :: Maybe Bool
mu = Just True

test1 = f do mt

test2 = f do mu

test3 = f do mt do mu

test4 = f do mt $ do mu

```

…which GHCi rejects:

```
# ghci BlockArgsBedlam.hs
GHCi, version 9.4.4: https://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling BlockArgsBedlam ( BlockArgsBedlam.hs, interpreted )

BlockArgsBedlam.hs:17:14: error:
    • Couldn't match expected type: Maybe Bool -> a0
                  with actual type: IO ()
    • The function ‘mt’ is applied to one value argument,
        but its type ‘IO ()’ has none
      In a stmt of a 'do' block: mt do mu
      In the first argument of ‘f’, namely ‘do mt do mu’
   |
17 | test3 = f do mt do mu
   | ^^^^^^^^

BlockArgsBedlam.hs:19:14: error:
    • Couldn't match expected type: Maybe Bool -> a1
                  with actual type: IO ()
    • In the first argument of ‘($)’, namely ‘mt’
      In a stmt of a 'do' block: mt $ do mu
      In the first argument of ‘f’, namely ‘do mt $ do mu’
   |
19 | test4 = f do mt $ do mu
   | ^^
Failed, no modules loaded.
ghci>
```

So `BlockArguments` is just another syntactic _“sugar rush”_ which doesn’t scale up for general use:

> [@](#):
>
> 1. Syntactic sugar causes cancer of the semicolon.
> 
> [Alan J. Perlis](https://dl.acm.org/doi/pdf/10.1145/947955.1083808)

…less of it is usually better.

---

<div class="post-metadata">

**Author:** ![Liamzy](https://avatars.discourse-cdn.com/v4/letter/l/50afbb/32.png) [@Liamzy](https://discourse.haskell.org/u/Liamzy)\
**Post date:** [August 9, 2023, 5:52pm UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/63 "2023-08-09T17:52:11Z")

</div>

TBH, the real drawback of language extensions is incessant arguing among engineers / developers over language extensions (which to use, whether they’re a good idea, and how they actually work).

But I agree with @Underlap; we need better documentation, specifically, tutorials, for the language extensions.

Haskell has come a long way from where every feature was essentially just documented by an academic paper, but Haskell documentation is not yet at the level where you can throw a codemonkey at it and get something that works.

Some Haskellers might feel this to be a feature, I feel this to be a bug.

---

<div class="post-metadata">

**Author:** ![AntC2](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/antc2/32/1872_2.png) [@AntC2](https://discourse.haskell.org/u/AntC2)\
**Post date:** [August 10, 2023, 12:22am UTC](https://discourse.haskell.org/t/maintaining-haskell-programs/7166/64 "2023-08-10T00:22:59Z")

</div>

> [@Underlap](#):
>
> I wanted to contribute to a Haskell project … and the first module I opened up used …

Thank you for relating your experience – this is almost worth a separate thread.

The whole document set got restructured at 9.0, which means a lot of material ended up in unfamiliar (to me) places. (Probably the new structure is more ‘logical’; it’s the changeover that’s leaving people disoriented.) And it’s been tweaked a bit since.

Specifically the docos on `FlexibleContexts` hasn’t got much terser AFAICT. Are you perhaps confusing with [`FlexibleInstances`](https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/instances.html?highlight=flexible#relaxed-rules-for-the-instance-head)? Which is indeed chunky, and rightfully so. I’da thought any project that uses one would use both.

> [@](#):
>
> [Type families](https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/type_families.html) looked harder.

Yep. And it’s not included in `GHC2021`/nor likely to be included in `GHC20XX`, so it’s not worth an ‘advanced Haskell’ tutorial that puts all these extensions together into some coherent explanatory whole.

The reason is there’s another approach in the same design space as `TypeFamilies`. `FunctionalDependencies` are older, but still widely used, and widely preferred for some purposes. (Although I suspect this is more to do with personal taste and familiarity.)

To achieve any sort of modern Haskell, your project will need one or the other; quite possibly both. (If you try to stick to one in your project, quite possibly some imports will use the other.)

I’d say Haskell is at that ‘awkward age’ between being a wild, experimental teenager and settling down with responsibilities. There isn’t (yet) the sort of corporate monoculture you get in more commercial languages.

[Previous page](https://discourse.haskell.org/t/maintaining-haskell-programs/7166.md?page=2)

[Next page](https://discourse.haskell.org/t/maintaining-haskell-programs/7166.md?page=4)
