auto-extract: Extract code segment to top level function

[ bsd3, development, library ] [ Propose Tags ] [ Report a vulnerability ]

Extract code segment to top level function using a GHC plugin


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.1.0.0
Change log CHANGELOG.md
Dependencies base (<5), bytestring (<0.13), containers, ghc (>=9.6 && <9.13), ghc-exactprint, ghc-paths, syb, transformers [details]
Tested with ghc ==9.12.1, ghc ==9.10.1, ghc ==9.8.1, ghc ==9.6.1
License BSD-3-Clause
Author Aaron Allen
Maintainer aaronallen8455@gmail.com
Category Development
Source repo head: git clone https://github.com/aaronallen8455/auto-extract
Uploaded by aaronallen8455 at 2025-11-08T22:25:02Z
Distributions
Downloads 2 total (2 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
All reported builds failed as of 2025-11-08 [all 1 reports]

Readme for auto-extract-0.1.0.0

[back to package description]

auto-extract 🍴

This is a GHC plugin that edits the file being compiled by extracting a target expression as a top level declaration. This is useful for breaking up large functions into smaller reusable pieces.

Usage

This plugin is intended to be used with GHCi or adjacent utilities such as ghcid and ghciwatch as a developement tool, not as a package dependency. Here is an example command for starting a REPL for a stack project with the auto-extract plugin enabled (you may need to add auto-extract to your extra-deps first):

stack repl my-project --package auto-extract --ghci-options='-fplugin AutoExtract'

likewise for a cabal project (you may need to run cabal update first):

cabal repl my-project --build-depends auto-extract --repl-options='-fplugin AutoExtract'

With the plugin enabled, mark the expression to be extracted using EXTRACT@name (<expr>) then compile the module. A top level definition will be added identified by the given name and having the expression enclosed in parens as the body. The plugin will determine what arguments are necessary and will include a type signature based on the inferred type of the expression. Compilation is aborted after the code is updated.

For example, given this program:

doubleInput :: IO ()
doubleInput = do
  input <- do
    putStrLn "Enter a number"
    readLn
  let doubled = input * 2
  print doubled

Insert the extraction targets:

doubleInput :: IO ()
doubleInput = do
  input <- EXTRACT@promptNumber (do
    putStrLn "Enter a number"
    readLn)
  let doubled = EXTRACT@double (input * 2)
  print doubled

Note: the code can contain multiple EXTRACT directives and they can be nested within one another.

Compiling the module will result in the source code being updated to:

doubleInput :: IO ()
doubleInput = do
  input <- promptNumber
  let doubled = double input
  print doubled

promptNumber :: IO Integer
promptNumber = do
  putStrLn "Enter a number"
  readLn

double :: Num a => a -> a
double input = input * 2

Caveats

  • The resulting module must pass the type checker in order for the code to be updated.
  • The plugin only supports certain GHC versions with the intent of supporting the four latest release series, i.e. 9.6.* thru 9.12.*. The cabal file indicates the currently supported versions.