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 <ekmett@gmail.com> wrote:
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


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.
  .
  > $ 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,
  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
  .
  > import Data.Map as Map
  .
  Additions to @Data.Map@ may clash with other identifiers,
  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