no-recursion 0.3.0.0 → 0.4.0.0
raw patch · 3 files changed
+126/−29 lines, 3 filesdep ~basedep ~ghc
Dependency ranges changed: base, ghc
Files
- CHANGELOG.md +12/−1
- README.md +74/−1
- no-recursion.cabal +40/−27
CHANGELOG.md view
@@ -5,6 +5,16 @@ The format is based on [Keep a Changelog 1.1](https://keepachangelog.com/en/1.1.0/), and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). +## [0.4.0.0] – 2026-01-15++### Added++- Support for GHC 9.14++### Removed++- Support for Cabal <3.10.3 (due to haskell/cabal#9375)+ ## [0.3.0.0] – 2025-11-05 ### Added@@ -77,10 +87,11 @@ - Initial release of this package. +[0.4.0.0]: https://github.com/sellout/no-recursion/compare/v0.3.0.0...v0.4.0.0 [0.3.0.0]: https://github.com/sellout/no-recursion/compare/v0.2.0.0...v0.3.0.0 [0.2.0.0]: https://github.com/sellout/no-recursion/compare/v0.1.2.3...v0.2.0.0 [0.1.2.3]: https://github.com/sellout/no-recursion/compare/v0.1.2.2...v0.1.2.3 [0.1.2.2]: https://github.com/sellout/no-recursion/compare/v0.1.2.0...v0.1.2.2 [0.1.2.0]: https://github.com/sellout/no-recursion/compare/v0.1.1.0...v0.1.2.0 [0.1.1.0]: https://github.com/sellout/no-recursion/compare/v0.1.0.0...v0.1.1.0-[0.1.0.0]: https://github.com/sellout/no-recursion/releases/tag/v0..1.0.0+[0.1.0.0]: https://github.com/sellout/no-recursion/releases/tag/v0.1.0.0
README.md view
@@ -1,5 +1,6 @@ # NoRecursion plugin +[](https://hackage.haskell.org/package/) [](https://repology.org/project/haskell:no-recursion/versions) [](https://repology.org/project/haskell:no-recursion/versions) @@ -103,6 +104,78 @@ Unfortunately, because `sconcat` (and `mconcat`) require lazy lists (`[]`), it’s not possible to write a total definition for these. +### mitigating [dependency hell](https://en.wikipedia.org/wiki/Dependency_hell)++As NoRecursion is effectively a linter, you don’t have to depend on it in every case (although, be careful, because different GHC versions may catch (or induce) different occurrences of recursion).++It’s easy to conditionalize the use of NoRecursion by adding the following (with a suitable replacement for `_`) to the stanzas in your Cabal file:++```cabal+ if _+ build-depends:+ no-recursion ^>= {x.y.z},+ ghc-options:+ -fplugin=NoRecursion+```++If the plugin isn’t enabled, any `-fplugin-opt=NoRecursion:…` elsewhere will simply be ignored.++Here are a couple concrete situations where this is useful.++#### you support a some environment that NoRecursion doesn’t++```cabal+ if impl(ghc >= 9.6.1) && impl(ghc < 9.14.1) && !arch(i386)+```++With the above condition, NoRecursion will only be used with GHC 9.6.1–9.12 and on architectures that aren’t i386 (32-bit).++Of course, we would love to have NoRecursion work in all your environments, so please [open an issue](https://github.com/sellout/no-recursion/issues/new?title=Add+support+for+&labels=dependencies,enhancement) if you find yourself using this approach. Since it’s a compiler plugin, it’s more sensitive to GHC changes than most code, so just ignoring dependency bounds is less likely to work.++#### you want to get out of consumers’ way++A common situation is depending on a version that isn’t widely available (this can happen with Stackage or maybe it’s an unpublished revision that you’ve added as a `source-repository-package`).++In this case, you can define a flag in your Cabal file++```cabal+flag verify-no-recursion+ description:+ Compile with "NoRecursion" enabled. This is intended for developers of this+ package.+ default: False+ manual: True+```++And then conditionalize on that++```cabal+ if flag(verify-no-recursion)+```++In cabal.project, you should also add++```cabal+flags:+ +verify-no-recursion+```++which will ensure that the flag doesn’t get automatically disabled when doing local development. You don’t want to discover that you had the `no-recursion` bounds set incorrectly only after a user complains that they can’t compile your library because of recursion errors.++If you’re using Stack, you can achieve the same thing with++```yaml+flags:+ local-package:+ verify-no-recursion: true+ another-local-package:+ verify-no-recursion: true+```++Note that with Stack you need to set the flag separately for each package in your project.++You can see an example of this (with Cabal) in the [duoids](https://github.com/sellout/duoids/blob/6de6468d173fdb8b95db3789d65984289b7b42d5/core/duoids.cabal#L64-L70) project.+ ## versioning This project largely follows the [Haskell Package Versioning Policy](https://pvp.haskell.org/) (PVP), but is more strict in some ways.@@ -185,7 +258,7 @@ ## licensing -This package is licensed under [The GNU AGPL 3.0 or later](./LICENSE). If you need a license for usage that isn’t covered under the AGPL, please contact [Greg Pfeil](mailto:greg@technomadic.org?subject=licensing%20no-recursion).+This package is licensed under [The GNU AGPL 3.0 only](./LICENSE). If you need a license for usage that isn’t covered under the AGPL, please contact [Greg Pfeil](mailto:greg@technomadic.org?subject=licensing%20no-recursion). You should review the [license report](docs/license-report.md) for details about dependency licenses.
no-recursion.cabal view
@@ -1,66 +1,77 @@ cabal-version: 3.0+-- ^ Cabal 3.0 is the first with the `Universal-FOSS-exception-1.0` SPDX license+-- exception. name: no-recursion-version: 0.3.0.0+version: 0.4.0.0 synopsis: A GHC plugin to remove support for recursion description: General recursion can be the cause of a lot of problems. This removes recursion from GHC, allowing you to guarantee you’re using other mechanisms, like recursion schemes.-author: Greg Pfeil <greg@technomadic.org> maintainer: Greg Pfeil <greg@technomadic.org>+author: Greg Pfeil <greg@technomadic.org> copyright: 2024 Greg Pfeil-homepage: https://github.com/sellout/no-recursion#readme-bug-reports: https://github.com/sellout/no-recursion/issues-category: Recursion-build-type: Custom -- TODO: Remove the redundant `OR AGPL-3.0-only` once -- haskell/hackage-server#1440 is fixed.-license: AGPL-3.0-only WITH Universal-FOSS-exception-1.0 OR AGPL-3.0-only OR LicenseRef-commercial+license: AGPL-3.0-only WITH Universal-FOSS-exception-1.0 OR LicenseRef-commercial license-files: LICENSE LICENSE.AGPL-3.0-only LICENSE.Universal-FOSS-exception-1.0 LICENSE.commercial+category: Recursion+build-type: Custom extra-doc-files: CHANGELOG.md README.md docs/*.md tested-with: GHC == {- 9.6.1, 9.6.3,+ 9.6.1, 9.6.7, 9.8.1, 9.8.4,- 9.10.1,- 9.12.1+ 9.10.1, 9.10.2, 9.10.3,+ 9.12.1, 9.12.2,+ 9.14.1 } +homepage: https://github.com/sellout/no-recursion#readme+bug-reports: https://github.com/sellout/no-recursion/issues source-repository head type: git location: https://github.com/sellout/no-recursion.git subdir: core +custom-setup+ setup-depends:+ -- TODO: Due to haskell/cabal#3751, `Cabal` has to be specified even though+ -- there’s no direct dependency. Its lower bound needs to be at least+ -- as high as `cabal-version` at the top of this file, and Hackage+ -- requires it to have _some_ upper bound. (Since there’s no direct+ -- dependency, it doesn’t use PVP bounds.)+ --+ -- TODO: Due to haskell/cabal#9375, 3.10.3 is required in order to load+ -- plugins from a `ghc-options` field. Unfortunately, GHCs prior to+ -- 9.8.3 include an older Cabal, so a newer one may need to be+ -- manually installed.+ Cabal >= 3.10.3 && < 99,+ base ^>= {4.18.0, 4.19.0, 4.20.0, 4.21.0, 4.22.0},+ cabal-doctest ^>= {1.0.0},+ flag noisy-deprecations description:- Prior to GHC 9.10, the `DEPRECATED` pragma can’t distinguish between terms+ Prior to GHC 9.10, the @DEPRECATED@ pragma can’t distinguish between terms and types. Consenquently, you can get spurious warnings when there’s a name collision and the name in the other namespace is deprecated. Or you can choose to not get those warnings, at the risk of not being warned when there’s a name collision and the namespace you’re referencing is the one that’s deprecated.--custom-setup- setup-depends:- -- TODO: Due to haskell/cabal#3751, `Cabal` has to be specified even though- -- there’s no direct dependency. Its lower bound needs to match- -- `cabal-version` at the top of this file, and Hackage requires it to- -- have _some_ upper bound. (Since there’s no direct dependency, it- -- doesn’t use PVP bounds.)- Cabal >= 3.0 && < 99,- base ^>= {4.18.0, 4.19.0, 4.20.0, 4.21.0},- cabal-doctest ^>= {1.0.0},+ default: True+ -- Because disabling this flag won’t help the solver.+ manual: True -- This mimics the GHC2024 extension -- (https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/control.html?highlight=doandifthenelse#extension-GHC2024),--- but supporting compilers back to GHC 8.0. If the oldest supported compiler+-- but supporting compilers back to GHC 7.10. If the oldest supported compiler -- is GHC 9.10, then this stanza can be removed and `import: GHC2024` can be -- replaced by `default-language: GHC2024`. If the oldest supported compiler is -- GHC 9.2, then this can be simplified by setting `default-language: GHC2021`@@ -80,7 +91,7 @@ common defaults import: GHC2024 build-depends:- base ^>= {4.18.0, 4.19.0, 4.20.0, 4.21.0},+ base ^>= {4.18.0, 4.19.0, 4.20.0, 4.21.0, 4.22.0}, ghc-options: -Weverything -- This one just reports unfixable things, AFAICT.@@ -121,9 +132,10 @@ library import: defaults- hs-source-dirs: src+ hs-source-dirs:+ src build-depends:- ghc ^>= {9.6.1, 9.8.1, 9.10.1, 9.12.1},+ ghc ^>= {9.6.1, 9.8.1, 9.10.1, 9.12.1, 9.14.1}, exposed-modules: NoRecursion other-modules:@@ -132,7 +144,8 @@ test-suite doctests import: defaults type: exitcode-stdio-1.0- hs-source-dirs: tests+ hs-source-dirs:+ tests main-is: doctests.hs build-depends: doctest ^>= {0.21.1, 0.22.2, 0.24.0},