Q Monad State

Ethan Pailes ethanpailes at gmail.com
Fri Mar 10 20:28:13 UTC 2017


Hi,

I've been working on PADS with Kathleen Fisher for the past couple of
months, and we have some questions about the Q Monad.

In working on extending the PADS language, we have encountered a need to
maintain a type environment across invocations of the [pads||] quasi
quoter. This allows PADS types to be defined in one quote block and used in
a later quote block. Unfortunately, the right way to do this is not obvious
from the Q Monad’s interface[1]. The monad provides `qGetQ` and `qPutQ`
methods to provide a place to store state across quotes, but unfortunately
this state is local to each module. It is desirable from a usability
perspective to be able to reuse PADS declarations across modules, but in
the particular case of PADS the problem is actually worse than that. PADS
ships with a standard library module which uses PADS to define several of
the core types required to be productive, so without the ability to do type
checking across modules the use of this standard library becomes
impossible. There are two solutions to the problem that we have considered.


   1.

   We can generate metadata about each type as it is defined and emit a top
   level declaration which contains this metadata.
   1.

      This clutters the global namespace.
      2.

      It lets you examine the metadata for each type easily in `ghci` which
      leads to a nice debugging workflow.
      3.

      If you want to perform any typechecks or other calculations based on
      the metadata, they must happen after generated code is spliced in.
      1.

         This means you lose a lot of type safety because everything must
         be represented as an `Exp` (even with typed template haskell
there is no
         way to get a type for an `Exp` of the form `VarE <<name of metadata>>`)
         2.

         It becomes impossible to report type errors at compile time. This
         is a dealbreaker because otherwise, what is the point?
         2.

   Using `unsafePerformIO` to create an IORef and then using the Q Monand’s
   `qRunIO` function to access the state cell.
   1.

      This works smoothly across modules
      2.

      You get type safety back because everything happens in the Q Monad.
      You don’t have to generate code in order to get at the values.
      3.

      It uses `unsafePerformIO` and `qRunIO` so you have to worry about how
      often everything gets run.
      1.

         It seems like it should be safe with a {-# NONINLINE #-} pragma
         for the code which creates the IORef.
         2.

         The IORef is hidden, and no one else should be able to modify it.
         3.

         Adding stuff to a `Data.Map.Strict` (the environment
         implementation we are using) is idempotent, so the quote code
getting run
         multiple times should not be an issue.


We have two main questions based on this.

   1.

   Is the IO (ab)use outlined above really as safe as we think it is?
   2.

   Given that environments are such a common requirement in compiling
   programming languages, and the goal of quasi quotation is allowing easy
   creation of EDSLs for Haskell, does it make sense to provide some state
   mechanism for the Q monad which is not restricted by modules.



[1]: https://hackage.haskell.org/package/template-haskell-2.11.
1.0/docs/Language-Haskell-TH-Syntax.html


Thanks,

Ethan Pailes
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/libraries/attachments/20170310/3ab8711b/attachment.html>


More information about the Libraries mailing list