Most projects accumulate code over time. Weeder detects unused Haskell exports, allowing dead code to be removed (pulling up the weeds). Weeder piggy-backs off files generated by
stack, so first obtain stack, then:
stack install weeder --resolver=nightly.
- Ensure your project has a
stack.yamlfile. If you don’t normally build with
stack initto generate one.
weeder . --build, which builds your project with
stackand reports any weeds.
What does Weeder detect?
Weeder detects a bunch of weeds, including:
- You export a function
Foo.Bar, but nothing else in your package uses
Foo.Baris not an
exposed-module. Therefore, the export of
helperis a weed. Note that
helperitself may or may not be a weed - once it is no longer exported
-fwarn-unused-bindswill tell you if it is entirely redundant.
- Your package
dependson another package but doesn’t use anything from it - the dependency should usually be deleted. This functionality is quite like packunused, but implemented quite differently.
- Your package has entries in the
other-modulesfield that are either unused (and thus should be deleted), or are missing (and thus should be added). The
stacktool warns about the latter already.
- A source file is used between two different sections in a
.cabalfile - e.g. in both the library and the executable. Usually it’s better to arrange for the executable to depend on the library, but sometimes that would unnecessarily pollute the interface. Useful to be aware of, and sometimes worth fixing, but not always.
- A file has not been compiled despite being mentioned in the
.cabalfile. This situation can be because the file is unused, or the
stackcompilation was incomplete. I recommend compiling both benchmarks and tests to avoid this warning where possible - running
weeder . --buildwill use a suitable command line.
Beware of conditional compilation (e.g.
CPP and the Cabal
flag mechanism), as these may mean that something is currently a weed, but in different configurations it is not.
I recommend fixing the warnings relating to
other-modules and files not being compiled first, as these may cause other warnings to disappear.
What else should I use?
Weeder detects dead exports, which can be deleted. To get the most code deleted from removing an export, use:
- GHC with
-fwarn-unused-binds -fwarn-unused-imports, which finds unused definitions and unused imports in a module.
- HLint, looking for “Redundant extension” hints, which finds unused extensions.
- Unused, which works at the level of
ctagsinformation, so can be used if you don’t want to use
stack, can’t compile your code, or want to detect unused code between projects.
If you want your package to be detected as “weed free”, but it has some weeds you know about but don’t consider important, you can add a
.weeder.yaml file adjacent to the
stack.yaml with a list of exclusions. To generate an initial list of exclusions run
weeder . --yaml > .weeder.yaml.
You may wish to generalise/simplify the
.weeder.yaml by removing anything above or below the interesting part. As an example of the
.weeder.yaml file from
- message: Module reused between components - message: - name: Weeds exported - identifier: withWaiterPoll
This configuration declares that I am not interested in the message about modules being reused between components (that’s the way
ghcid works, and I am aware of it). It also says that I am not concerned about
withWaiterPoll being a weed - it’s a simplified method of file change detection I use for debugging, so even though it’s dead now, I sometimes do switch to it.
Running with Continuous Integration
Before running Weeder on your continuous integration (CI) server, you should first ensure there are no existing weeds. One way to achieve that is to ignore existing hints by running
weeder . --yaml > .weeder.yaml and checking in the resulting
On the CI you should then run
weeder . (or
weeder . --build to compile as well). To avoid the cost of compilation you may wish to fetch the latest Weeder binary release. For certain CI environments there are helper scripts to do that.
Travis: Execute the following command:
curl -sSL https://raw.github.com/ndmitchell/weeder/master/misc/travis.sh | sh -s .
The arguments after
-s are passed to
weeder, so modify the final
. if you want other arguments.
Appveyor: Add the following statement to
- ps: Invoke-Command ([Scriptblock]::Create((Invoke-WebRequest 'https://raw.githubusercontent.com/ndmitchell/weeder/master/misc/appveyor.ps1').Content)) -ArgumentList @('.')
The arguments inside
@() are passed to
weeder, so add new arguments surrounded by
', space separated - e.g.
What about Cabal users?
Weeder requires the textual
.hi file for each source file in the project. Stack generates that already, so it was easy to integrate in to. There’s no reason that information couldn’t be extracted by either passing flags to Cabal, or converting the
.hi files afterwards. I welcome patches to do that integration.
What about false positives?
Weeder strives to avoid incorrectly warning about something that is required, if you find such an instance please report it on the issue tracker. Unfortunately there are some cases where there are still false positives, as GHC doesn’t put enough information in the
Data.Coerce If you use
Data.Coerce.coerce the constructors for the data type must be in scope, but if they aren’t used anywhere other than automatically by
coerce then Weeder will report unused imports. You can ignore such warnings by adding
- message: Unused import to your
Declaration QuasiQuotes If you use a declaration-level quasi-quote then weeder won’t see the use of the quoting function, potentially leading to an unused import warning, and marking the quoting function as a weed. The only solution is to ignore the entries with a
Stack extra-deps Packages marked extra-deps in your
stack.yaml will be weeded, due to a bug in
stack. The only solution is to ignore the packages with a
Linking to C functions If a library provides C functions, and these are used directly from another library/executable, the library providing these functions may be marked as a redundant
build-depends, see more details.
1.0.8, released 2018-08-26
#42, make paths case-insensitive on MacOS
1.0.7, released 2018-08-23
Don't warn on base as it is used by Paths_ modules
#42, make --verbose print out the version number
#41, make the --help output clear you can pass a stack.yaml
1.0.6, released 2018-06-16
Don't fail with an error if stack setup is necessary
If you fail to find stack.yaml give a better error message
1.0.5, released 2018-05-05
#39, provide weeder as a library
1.0.4, released 2018-05-02
#38, make sure you parse bracketed version ranges properly
1.0.3, released 2018-03-04
#35, support ^>= operator in Cabal
1.0.2, released 2018-03-01
Add lower bounds for Yaml and Aeson
1.0.1, released 2018-02-23
#34, support -any for version numbers
1.0, released 2018-01-22
#30, bump the version number to 1.0
0.1.13, released 2018-01-17
#32, find .hi files in more places
#32, always disable color when running stack
0.1.12, released 2018-01-16
Make available on Mac
0.1.11, released 2017-12-29
#29, deal with case-insensitive FilePath on Windows
0.1.10, released 2017-12-28
Make --verbose print out the directory when running commands
Don't report semigroups as unused on any platforms
0.1.9, released 2017-12-07
Don't report Win32/unix as unused on the alternate platform
0.1.8, released 2017-12-06
Follow both branches for if/else containing dependencies/modules
0.1.7, released 2017-08-09
#21, detect dependencies that are only required transitively
#13, respect the STACK_YAML environment variable
#20, add verbosity messages in a lot of places
#15, tone down unused import if exporting a cross-package type
#11, optimise execution speed (~3x faster)
0.1.6, released 2017-06-18
#10, find files generated by alex/happy
0.1.5, released 2017-06-02
If --yaml and no hints give no output
0.1.4, released 2017-05-27
#9, allow --dist-dir to set the stack dist-dir
Deal with operators including | in them
Allow arrays of arrays of strings in the .weeder.yaml
0.1.3, released 2017-05-08
#5, document how to install weeder
#8, detect unused imports, even import Foo()
#7, don't say modules with only instances are always redundant
#6, don't give partial pattern matches when reading .weeder.yaml
0.1.2, released 2017-04-29
#3, deal with space-separated hs-source-dirs
0.1.1, released 2017-04-29
#2, use "stack query" rather than parsing stack.yaml
0.1, released 2017-04-28