Writing GHC plugin to modify AST despite failure to type-check

Evan Relf evan at evanrelf.com
Thu Jul 1 01:56:07 UTC 2021


Hi there,

I would like to write a GHC plugin — initially as a learning exercise, and maybe real-world use if it works — that automatically applies `liftIO` to `IO` actions, to get the benefit that libraries like `lifted-base` or `relude` provide, but applied to all libraries, automatically.

As a simple example, this program will not type-check by default, but it will if I can write my plugin:

```
program :: MonadIO m => m ()
program = putStrLn "Hello world!"
```

(That's `putStrLn :: String -> IO ()` from the regular `Prelude`)

The idea is roughly, "if you see an `IO a` action where a `MonadIO m => m a` action is expected, add `liftIO` to make the `IO a` action type-check. But how to implement it?

A type-checker plugin runs when type-checking fails, which is when I want to take action. But it doesn't seem to allow me to change the AST so I can add the `liftIO` function. So then I tried...

A `typeCheckResultAction` plugin (for lack of a better name) does allow me to change the AST, and I can use the types to guide how I do it. But it doesn't seem to run if type-checking fails, which is exactly when I want to be adding the `liftIO`s.

Am I missing something about GHC's plugin system that would allow me to do what I want? Whether that be AST manipulation in a type-checking plugin, or running the `typeCheckResultAction` despite type-checking failing. Or is AST manipulation with type information impossible if type-checking fails?

This is my first foray into anything GHC-related, so I apologize if this doesn't make sense, or isn't the right place to ask.

Thanks,

- Evan


More information about the ghc-devs mailing list