Skip to content

Support for common stanzas #569

Open

Description

@ramirez7

I saw this #513

I'm opening a new issue about the same thing.

YAML includes are inadequate for DRYing up even moderately-complex cabal config. Mostly due to the lack of recursive merge.

For instance, if I define a shared YAML file with default-extensions for my entire monorepo but a single package wants to add another default-extension just for itself, it clobbers the include. There's no good way around this using just YAML includes.

Now, if I could use cabal common stanzas, then YAML includes could help me:

  • I could define the common stanzas in shared YAML across my monorepo
  • My individual packages' package.yaml could include the common stanzas
  • Each package.yaml could then use cabal import accordingly.

I guess an alternative would be for hpack to add support for proper YAML recursive merge. But even if it had that, I don't see why hpack shouldn't support the cabal feature.

Activity

  1. ramirez7 commented on Oct 2, 2023

    @ramirez7
    Author

    (This seems like a pretty trivial feature to add, so if I find time, I'll just add it myself ✌️)

  2. MrQubo commented on Dec 16, 2023

    @MrQubo

    That's so much needed. I've tried using hpack a few times, but always had to go back to using Cabal.

    YAML's anchors are rarely enough. E.g. you can't use it with ghc-options, because this is a list and YAML doesn't support list concatenation. You can hack it like this (but that's very ugly):

    when:
      - condition: true
        ghc-options: *ghc-options-warnings
      - condition: true
        ghc-options: *ghc-options-opt
  3. sellout commented on Oct 21, 2025

    @sellout

    I would really love this feature. I know (as seen in #522) that it can be “faked“ using

    verbatim: |
      common stuff
        ghc-options: -Weverything
    
    library:
      verbatim:
        import: stuff

    but encoding the common stanza as a string is not ideal. In particular, I create the elements of common programmatically, so it’s easier to use YAML anchors across the target stanzas, but that results in a much worse Cabal file (and I do think readability of the Cabal file is important, as it’s what’s included in the package).

    I can imagine another complication here could be hpack’s inference of other fields, since it might then need to track which common stanzas are imported to which sections, whereas verbatim, is specifically not taken into account.

    When I first used hpack, I was initially surprised that using common fields at the top level caused them to be duplicated to each section, rather than introduce a common stanza that was then imported to every section. I think if common is supported, common fields at the top level shouldn’t change how they work. I would change my usage to only have import at the top level (duplicated to all my sections) and then define an explicit common stanza for the things that I used to include at the top level. For example:

    ghc-options: -Weverything

    would become

    common:
      defaults:
        ghc-options: -Weverything
    import:
    - defaults

    which (at least for such a tiny example) makes the package.yaml more verbose, but vastly cleans up the Cabal file. (And, as indicated in that example, import should be a list.)

  4. sol commented on Oct 23, 2025

    @sol
    Owner

    Before writing a more comprehensive response:

    1. Have you looked at https://github.com/sol/hpack?tab=readme-ov-file#defaults? We could possibly extent this to allow defining defaults sections in the same file + we could introduce better terminology (e.g. add use as an alias for defaults).
    2. Historically, Cabal did not support common sections. That is the reason why Hpack could not desugar top-level fields to common sections. This would possibly be an option now, sacrificing Cabal version support for a "cleaner" .cabal file. As it is not entirely clear to me whether sacrificing something functional for something aesthetic is an improvement, this is not particularly high on my priority list. It would also be a breaking change that I'm not entirely sure how we should deal with. I kind of assume that if you had an old package.yaml and you run a new version of hpack then you would expect a functionally equivalent .cabal file (and I think that includes the required cabal-version). We may eventually need to make a pragmatic cut at some point. The question is whether a purely cosmetic change is a good enough reason for that.
  5. sol commented on Oct 23, 2025

    @sol
    Owner

    YAML includes are inadequate for DRYing up even moderately-complex cabal config. Mostly due to the lack of recursive merge.

    For instance, if I define a shared YAML file with default-extensions for my entire monorepo but a single package wants to add another default-extension just for itself, it clobbers the include. There's no good way around this using just YAML includes.

    YAML anchors are not the primary mechanism to DRY up Hpack package descriptions.

    You should either use top-level fields and/or defaults for this.

    YAML anchors work on the syntactic level, which comes with some limitations. Think of them as something akin to CPP for yaml/hpack. They are an additional tool that can be useful in certain situations, but they are not a replacement for defaults.

  6. sellout commented on Oct 28, 2025

    @sellout
    1. Have you looked at https://github.com/sol/hpack?tab=readme-ov-file#defaults? We could possibly extent this to allow defining defaults sections in the same file + we could introduce better terminology (e.g. add use as an alias for defaults).

    Yes, but I don’t think this helps in my case. I have no issue with using top-level common fields in the package.yaml file.

    1. Historically, Cabal did not support common sections. That is the reason why Hpack could not desugar top-level fields to common sections. This would possibly be an option now, sacrificing Cabal version support for a "cleaner" .cabal file.

    I think my message was a bit confusing. I don’t want top-level fields to desugar to common sections1. I like the way top-level fields work now. But I would like to be able to explicitly define common sections and correspondingly add import to the hpack “common fields”.

    Footnotes

    1. That was just a misconception I had when I first encountered hpack. ↩

  7. sol commented on Oct 29, 2025

    @sol
    Owner

    @sellout again, have you tried to solve your use case with defaults? Does this work, and if not, where exactly do you hit the wall?

    Note that defaults currently need to live in a separate file, which is something we could address if there is demand for it (e.g. adding support for defining defaults within the same file).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions