You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
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):
I would really love this feature. I know (as seen in #522) that it can be “faked“ using
verbatim: | common stuff ghc-options: -Weverythinglibrary:
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:
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.)
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).
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.
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.
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.
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
That was just a misconception I had when I first encountered hpack. ↩
@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).
Activity
ramirez7 commentedon Oct 2, 2023
(This seems like a pretty trivial feature to add, so if I find time, I'll just add it myself ✌️)
MrQubo commentedon Dec 16, 2023
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):
sellout commentedon Oct 21, 2025
I would really love this feature. I know (as seen in #522) that it can be “faked“ using
but encoding the
commonstanza as a string is not ideal. In particular, I create the elements ofcommonprogrammatically, 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
commonstanzas are imported to which sections, whereasverbatim, 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
commonstanza that was thenimported to every section. I think ifcommonis supported, common fields at the top level shouldn’t change how they work. I would change my usage to only haveimportat the top level (duplicated to all my sections) and then define an explicitcommonstanza for the things that I used to include at the top level. For example:would become
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,
importshould be a list.)sol commentedon Oct 23, 2025
Before writing a more comprehensive response:
defaultssections in the same file + we could introduce better terminology (e.g. adduseas an alias fordefaults)..cabalfile. 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 oldpackage.yamland you run a new version ofhpackthen you would expect a functionally equivalent.cabalfile (and I think that includes the requiredcabal-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.sol commentedon Oct 23, 2025
YAML anchors are not the primary mechanism to DRY up Hpack package descriptions.
You should either use top-level fields and/or
defaultsfor 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.sellout commentedon Oct 28, 2025
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.
I think my message was a bit confusing. I don’t want top-level fields to desugar to
commonsections1. I like the way top-level fields work now. But I would like to be able to explicitly definecommonsections and correspondingly addimportto the hpack “common fields”.Footnotes
That was just a misconception I had when I first encountered hpack. ↩
sol commentedon Oct 29, 2025
@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
defaultscurrently need to live in a separate file, which is something we could address if there is demand for it (e.g. adding support for definingdefaultswithin the same file).