GHC Stage Restrictions and `stack script`

Posted on February 25, 2020

GHC Stage Restrictions and stack script

I love stack script

It does a few things really well:

  1. self-contained example
  2. pinned dependencies, the script is reliably reproducible

However, there are some limits.

One such limit is the restrictions inherent in the build/compilation stages GHC must take as different iterations over the code. In other words, generated code, such as with Template Haskell (TH), will not work right if there is an overlap within a single module (TH that defines some construct within a module that also uses those constructs).

With stack script, you would generally have the code in one file, one module, and that would run into the stage restriction. For example:

import Yesod.Core

data App = App

mkYesodData "App" $(parseRoutesFile "routes")

instance Yesod App

mkYesodDispatch "App" resourcesApp

main :: IO ()
main = warp 3000 App

yields:

hello-world/Main.hs:56:23: error:
    GHC stage restriction:
      ‘resourcesApp’ is used in a top-level splice, quasi-quote, or annotation,
      and must be imported, not defined locally
   |
56 | mkYesodDispatch "App" resourcesApp
   |                       ^^^^^^^^^^^^

See also..

https://stackoverflow.com/questions/16348183/template-haskell-ghc-stage-restriction-and-how-to-overcome https://stackoverflow.com/questions/9979715/how-to-circumvent-ghc-stage-restriction

How to work around this?

Black magic that isn’t worth using except to learn about, https://github.com/TerrorJack/template-haskell-jailbreak

Maybe there are other ways, but I am not familiar.