
I second that sentiment of appreciation. As much as we all disagree on
some things, we all agree you make a tremendous amount of neat code
available to the community.
On Friday, February 28, 2014, Edward Kmett
I just want to say thank you for writing this tool.
I may not agree with your interpretation of the PVP on this particular issue, and will probably only use it on a couple of smaller packages that have almost no imports, but at least putting code out there to help those who do want to work in that style is a very helpful and valuable thing.
-Edward
On Fri, Feb 28, 2014 at 3:10 PM, Henning Thielemann < schlepptop@henning-thielemann.de> wrote:
I got distracted by writing a tool that checks consistency of package dependencies and import styles. It's not yet perfect, but usable:
https://hackage.haskell.org/package/check-pvp
$ check-pvp . This requires that the package is configured, since only then the association of packages to modules is known. If you want to run the tool on a non-configured package you may just check all imports for addition-proof style. . $ check-pvp --include-all . It follows a detailed description of the procedure and the rationale behind it. . First the program classifies all dependencies in the Cabal file of the package. You can show all classifications with the @--classify-dependencies@option, otherwise only problematic dependencies are shown. . A dependency like @containers >=0.5.0.3 && <0.5.1@ does not allow changes of the API of @containers@ and thus the program does not check its imports. Clashing import abbreviations are an exception. . The dependency @containers >=0.5.1 && <0.6@ requires more care when importing modules from @containers@ and this is what the program is going to check next. This is the main purpose of the program! I warmly recommend this kind of dependency range since it greatly reduces the work to keep your package going together with its imported packages. . Dependencies like @containers >=0.5@ or @containers >=0.5 && <1@ are always problematic, since within the specified version ranges identifier can disappear. There is no import style that protects against removed identifiers. . An inclusive upper bound as in @containers >=0.5 && <=0.6@ will also cause a warning, because it is unnecessarily strict. If you know that @containers-0.6@ works for you,
import Data.Map as Map . Additions to @Data.Map@ may clash with other identifiers,
Description: Check whether the version ranges used in the @Build-Depends@ field matches the style of module imports according to the Package Versioning Policy (PVP). See http://www.haskell.org/haskellwiki/Package_versioning_policy. The tool essentially looks for any dependency like @containers >=0.5 && <0.6@ that allows the addition of identifiers to modules within the version range. Then it checks whether all module imports from @containers@ are protected against name clashes that could be caused by addition of identifiers. . You must run the tool in a directory containing a Cabal package. . then @containers-0.6.0.1@ or @containers-0.6.1@ will also work, depending on your import style. A special case of inclusive upper bounds are specific versions like in @containers ==0.6@. The argument for the warning remains the same. . Please note that the check of ranges is performed entirely on the package description. The program will not inspect the imported module contents. E.g. if you depend on @containers >=0.5 && <0.6@ but import in a way that risks name clashes, then you may just extend the dependency to @containers >=0.5 && <0.6.1@ in order to let the checker fall silent. If you use the dependency @containers >=0.5 && <0.6.1@ then the checker expects that you have verified that your package works with all versions of kind @0.5.x@ and the version @0.6.0@. Other versions would then work, too, due to the constraints imposed by package versioning policy. . Let us now look at imports that must be protected against identifier additions. . The program may complain about a lax import. This means you have imported like . thus you must import either .
import qualified Data.Map as Map . or . import Data.Map (Map) . The program may complain about an open list of constructors as in . import Data.Sequence (ViewL(..)) . Additions of constructors to @ViewL@ may also conflict with other identifiers. You must instead import like . import Data.Sequence (ViewL(Empt