diff --git a/doc/cabal-package.rst b/doc/cabal-package.rst index 093f94a823c..7a90399b08f 100644 --- a/doc/cabal-package.rst +++ b/doc/cabal-package.rst @@ -2171,7 +2171,20 @@ system-dependent values for these fields. Supported only in GHC 8.2 and later. A list of packages mentioned in the :pkg-field:`build-depends` field, each optionally accompanied by a list of - module and module signature renamings. + module and module signature renamings. A valid mixin obeys the + following syntax: + + :: + + Mixin ::= PackageName IncludeRenaming + IncludeRenaming ::= ModuleRenaming { "requires" ModuleRenaming } + ModuleRenaming ::= + {- empty -} + | "(" Renaming "," ... "," Renaming ")" + | "hiding" "(" ModuleName "," ... "," ModuleName ")" + Renaming ::= + ModuleName + | ModuleName "as" ModuleName The simplest mixin syntax is simply the name of a package mentioned in the :pkg-field:`build-depends` field. For example: @@ -3333,6 +3346,114 @@ a few options: library for all or part of the work. One option is to copy the source of ``Distribution.Simple``, and alter it for your needs. Good luck. +.. _Backpack: + +Backpack +-------- + +Cabal and GHC jointly support Backpack, an extension to Haskell's module +system which makes it possible to parametrize a package over some +modules, which can be instantiated later arbitrarily by a user. This +means you can write a library to be agnostic over some data +representation, and then instantiate it several times with different +data representations. Like C++ templates, instantiated packages are +recompiled for each instantiation, which means you do not pay any +runtime cost for parametrizing packages in this way. Backpack modules +are somewhat experimental; while fully supported by cabal-install, they are currently +`not supported by Stack `__. + +A Backpack package is defined by use of the +:pkg-field:`library:signatures` field, or by (transitive) dependency on +a package that defines some requirements. To define a parametrized +package, define a signature file (file extension ``hsig``) that +specifies the signature of the module you want to parametrize over, and +add it to your Cabal file in the :pkg-field:`library:signatures` field. + +.. code-block:: haskell + :caption: .hsig + + signature Str where + + data Str + + concat :: [Str] -> Str + +.. code-block:: cabal + :caption: parametrized.cabal + + cabal-version: 2.2 + name: parametrized + + library + build-depends: base + signatures: Str + exposed-modules: MyModule + +You can define any number of regular modules (e.g., ``MyModule``) that +import signatures and use them as regular modules. + +If you are familiar with ML modules, you might now expect there to be +some way to apply the parametrized package with an implementation of +the ``Str`` module to get a concrete instantiation of the package. +Backpack operates slightly differently with a concept of *mix-in +linking*, where you provide an implementation of ``Str`` simply by +bringing another module into scope with the same name as the +requirement. For example, if you had a package ``str-impl`` that provided a +module named ``Str``, instantiating ``parametrized`` is as simple as +just depending on both ``str-impl`` and ``parametrized``: + +.. code-block:: cabal + :caption: combined.cabal + + cabal-version: 2.2 + name: combined + + library + build-depends: base, str-impl, parametrized + +Note that due to technical limmitations, you cannot directly define +``Str`` in the ``combined`` library; it must be placed in its own +library (you can use :ref:`Internal Libraries ` to conveniently +define a sub-library). + +However, a more common situation is that your names don't match up +exactly. The :pkg-field:`library:mixins` field can be used to rename +signatures and modules to line up names as necessary. If you have +a requirement ``Str`` and an implementation ``Data.Text``, you can +line up the names in one of two ways: + +* Rename the requirement to match the implementation: + ``mixins: parametrized requires (Str as Data.Text)`` +* Rename the implementation to match the requirement: + ``mixins: text (Data.Text as Str)`` + +The :pkg-field:`library:mixins` field can also be used to disambiguate +between multiple instantiations of the same package; for each +instantiation of the package, give it a separate entry in mixins with +the requirements and provided modules renamed to be distinct. + +.. code-block:: cabal + :caption: .cabal + + cabal-version: 2.2 + name: double-combined + + library + build-depends: base, text, bytestring, parametrized + mixins: + parametrized (MyModule as MyModule.Text) requires (Str as Data.Text), + parametrized (MyModule as MyModule.BS) requires (Str as Data.ByteString) + +Intensive use of Backpack sometimes involves creating lots of small +parametrized libraries; :ref:`Internal Libraries ` can be used +to define all of these libraries in a single package without having to +create many separate Cabal packages. You may also find it useful to use +:pkg-field:`library:reexported-modules` to reexport instantiated +libraries to Backpack-unware users (e.g., Backpack can be used entirely +as an implementation detail.) + +For more information about Backpack, check out the +`GHC wiki page `__. .. include:: references.inc diff --git a/doc/file-format-changelog.rst b/doc/file-format-changelog.rst index f23c649551f..52116db5879 100644 --- a/doc/file-format-changelog.rst +++ b/doc/file-format-changelog.rst @@ -159,7 +159,7 @@ relative to the respective preceding *published* version. ---------------------- * New :pkg-field:`library:signatures` and :pkg-field:`mixins` fields - added for supporting Backpack_. + added for supporting :ref:`Backpack`. * New :pkg-field:`build-tool-depends` field added for adding build-time dependencies of executable components. diff --git a/doc/references.inc b/doc/references.inc index ede4dc6622c..2d586719615 100644 --- a/doc/references.inc +++ b/doc/references.inc @@ -22,5 +22,3 @@ .. _cpphs: http://projects.haskell.org/cpphs/ .. _ABNF: https://tools.ietf.org/html/rfc5234 - -.. _Backpack: https://gitlab.haskell.org/ghc/ghc/-/wikis/backpack