`ghc-pkg list` seems to be quadratic in the number of packages
## Summary
Running `ghc-pkg list` seems to be quadratic in the number of packages.
```
> time ghc-pkg-9.10.3 -f ~/.local/state/cabal/store/ghc-9.10.3-415c/package.db/ list | wc -l
5886
________________________________________________________
Executed in 4.33 secs fish external
usr time 4.09 secs 0.55 millis 4.09 secs
sys time 0.17 secs 1.02 millis 0.17 secs
```
A quick profile pointed to `closure` inefficient.
## Steps to reproduce
AI Generated script to populate a package db with lots of stuff, so don't expect anything of it.
```
GHC="path/to/ghc" # or just `ghc`
COMMON="--allow-newer=base,template-haskell,ghc,ghc-prim,bytestring,text,containers,deepseq,time,Cabal,Cabal-syntax,transformers,mtl,filepath,directory,process,ghc-bignum --constraint=hashable==1.4.7.0"
run_batch() {
local BATCH_NAME="$1"
shift
echo "=== Batch: $BATCH_NAME ==="
for FLAVOR in \
"" \
"--enable-profiling --enable-library-profiling" \
"--enable-executable-dynamic --enable-shared" \
"--enable-library-profiling --enable-profiling --enable-shared" \
"--enable-debug-info=2" \
"--disable-optimization" \
"--ghc-options=-O2 --ghc-options=-fexpose-all-unfoldings"; do
cabal install -w "$GHC" $COMMON $FLAVOR "$@" ||
echo " skip flavor: $FLAVOR"
done
}
run_batch "core" \
text bytestring containers unordered-containers vector \
hashable scientific \
mtl transformers async stm
run_batch "parsing" \
attoparsec megaparsec parsec optparse-applicative \
aeson yaml cassava aeson-pretty
run_batch "web-core" \
network network-uri http-types http2 websockets \
http-client http-client-tls wai warp wai-extra \
req http-conduit
run_batch "streaming" \
conduit pipes streaming
run_batch "servant" \
servant servant-server servant-client \
servant-swagger swagger2 openapi3
run_batch "lenses" \
lens generic-lens generic-optics \
microlens-platform optics optics-th lens-aeson
run_batch "fp-extras" \
free recursion-schemes profunctors comonad \
these semialign witherable extra safe split \
fgl algebraic-graphs
run_batch "testing" \
tasty tasty-hunit tasty-quickcheck hspec QuickCheck hedgehog \
criterion gauge tasty-bench weigh
run_batch "crypto-tls" \
cryptonite cryptohash-sha256 x509 x509-store tls connection
run_batch "db" \
persistent persistent-sqlite esqueleto \
postgresql-simple postgresql-libpq mysql-simple sqlite-simple \
acid-state safecopy
run_batch "misc" \
random uuid time process typed-process shake \
blaze-html lucid clay shakespeare \
inline-c language-c language-javascript
run_batch "parallel" \
parallel monad-par massiv repa
run_batch "cabal-libs" \
cabal-install-solver Cabal Cabal-syntax
run_batch "haskell-meta" \
haskell-src-exts haskell-src-meta hint
run_batch "pandoc" \
pandoc pandoc-types texmath skylighting skylighting-core citeproc
run_batch "diagrams" \
diagrams diagrams-lib diagrams-svg diagrams-contrib \
gloss Chart Chart-diagrams
run_batch "amazonka" \
amazonka amazonka-s3 amazonka-ec2 amazonka-dynamodb
run_batch "web-frameworks" \
hakyll yesod yesod-core yesod-form yesod-auth
run_batch "hls" \
ghcide hls-plugin-api
run_batch "dhall" \
dhall
```
Then run the appropriate `ghc-pkg` invocation once more than 1000 packages are installed.
## Expected behavior
Should be faster :)
## Environment
* GHC version used: 9.10.3 and HEAD 38b76b2f1d918f10d2f9d3e57bd0459dfe671d4f
Optional:
* Operating System: arch linux
* System Architecture: x86_64
issue