<div dir="ltr">> <span style="font-size:12.8px">I don't see any writing of the IORef in this example.  Indeed, if I add</span><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">That makes sense.</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">> </span><span style="font-size:12.8px">Could use findCabalFile from</span></div>> <a href="https://hackage.haskell.org/package/th-utilities-0.2.0.1/docs/TH-RelativePaths.html" rel="noreferrer" target="_blank" style="font-size:12.8px">https://hackage.haskell.org/<wbr>package/th-utilities-0.2.0.1/<wbr>docs/TH-RelativePaths.html</a><br style="font-size:12.8px"><span style="font-size:12.8px">> to find the cabal file, take the dir that file is in, and add</span><br style="font-size:12.8px"><span style="font-size:12.8px">> "/.stack-work" to it.</span><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">That sounds promising. Thanks for your help. It seems like writing little metadata files to .stack-work or a similar location for cabal based projects is the best way to do things.</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">Ethan </span><br><div><span style="font-size:12.8px"><br></span><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px"><br></span></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Mar 11, 2017 at 1:43 AM, Michael Sloan <span dir="ltr"><<a href="mailto:mgsloan@gmail.com" target="_blank">mgsloan@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Fri, Mar 10, 2017 at 6:22 PM, Ethan Pailes <<a href="mailto:ethanpailes@gmail.com">ethanpailes@gmail.com</a>> wrote:<br>
> I had not considered the issue about incremental compilation. It certainly<br>
> feels like it should cause problems. I wanted to confirm your suspicious, so<br>
> I threw together an example project which is meant to cause the issues that<br>
> you mentioned, but I was unable to produce any sort of error. I've thrown<br>
> the code up at <a href="https://github.com/ethanpailes/th-ioref" rel="noreferrer" target="_blank">https://github.com/<wbr>ethanpailes/th-ioref</a> if you want to take a<br>
> look. Basically there is a Ref module which makes an IORef, then a Quote<br>
> module which reads it and a Lib module which uses the Quote module to add a<br>
> top level value which depends on the contents of the IORef. I tried building<br>
> it, then just modifying Quote and rebuilding. I was expecting exactly the<br>
> sort of error you described, but everything works fine. When I added an<br>
> executable which depends on the library, that also works fine. I feel like<br>
> there should be an error though, so I would appreciate it if you could take<br>
> a look at the code and try to figure out how to produce the sort of error<br>
> that it seems like should occur. If it turns out that this does actually<br>
> work, it would be great to know why because your point really seems like it<br>
> should be right.<br>
<br>
</span>I don't see any writing of the IORef in this example.  Indeed, if I add<br>
<br>
$(runIO (writeIORef ref 5) >> return [])<br>
<br>
To Lib.hs, it still just prints out 4 for both.  You *really* won't be<br>
able to have the IORef transfer info from Lib.hs to Main.hs, since<br>
they are in different cabal components and so will be compiled by<br>
different invocations of ghc.<br>
<span class=""><br>
>> A third approach to consider is to just write out a file for each module,<br>
>> listing the metadata.  When compiling other modules, you can use<br>
>> `reifyModules` to get the imports, so that you know which metadata files to<br>
>> load.  One issue with this (as well as the IORef) is that it won't work<br>
>> across multiple packages.<br>
><br>
> Do you know if there is a way to learn where the build output is going in<br>
> the Q Monad? It would be much better to write the tmp files out to some<br>
> place in .stack_work rather than in /tmp. That way if /tmp disappears we<br>
> don't loose the cached data.<br>
<br>
</span>Could use findCabalFile from<br>
<a href="https://hackage.haskell.org/package/th-utilities-0.2.0.1/docs/TH-RelativePaths.html" rel="noreferrer" target="_blank">https://hackage.haskell.org/<wbr>package/th-utilities-0.2.0.1/<wbr>docs/TH-RelativePaths.html</a><br>
to find the cabal file, take the dir that file is in, and add<br>
"/.stack-work" to it.<br>
<div class="HOEnZb"><div class="h5"><br>
> Ethan<br>
><br>
> On Fri, Mar 10, 2017 at 5:47 PM, Michael Sloan <<a href="mailto:mgsloan@gmail.com">mgsloan@gmail.com</a>> wrote:<br>
>><br>
>> Hi!<br>
>><br>
>> I don't think the IORef approach will work well, because GHC won't<br>
>> recompile modules unless they've changed (or if a file added via<br>
>> qAddDependentFile changes).  So if you've done a compile of module A, and B<br>
>> depends on it, and then you just change B, only B will recompile and you<br>
>> won't have info from A.<br>
>><br>
>> Not sure if this applies to your circumstance, but one issue with the top<br>
>> level declaration approach is that TH can't enumerate the members of a<br>
>> module.  One hacky way to write down such metadata in a retrievable way is<br>
>> to use typeclass instances.  For example you might have<br>
>><br>
>> class TypeInfo (name :: Symbol) (typeInfo :: Symbol)<br>
>><br>
>> Then, you can reify the typeclass to get all its instances.  As long as<br>
>> you only need to write out this info from declaration quasiquotes, this info<br>
>> ought to be available for typechecking later in the module.<br>
>><br>
>> A third approach to consider is to just write out a file for each module,<br>
>> listing the metadata.  When compiling other modules, you can use<br>
>> `reifyModules` to get the imports, so that you know which metadata files to<br>
>> load.  One issue with this (as well as the IORef) is that it won't work<br>
>> across multiple packages.<br>
>><br>
>> -Michael<br>
>><br>
>> On Fri, Mar 10, 2017 at 12:29 PM Ethan Pailes <<a href="mailto:ethanpailes@gmail.com">ethanpailes@gmail.com</a>><br>
>> wrote:<br>
>>><br>
>>> Hi,<br>
>>><br>
>>> I've been working on PADS with Kathleen Fisher for the past couple of<br>
>>> months, and we have some questions about the Q Monad.<br>
>>><br>
>>> In working on extending the PADS language, we have encountered a need to<br>
>>> maintain a type environment across invocations of the [pads||] quasi quoter.<br>
>>> This allows PADS types to be defined in one quote block and used in a later<br>
>>> quote block. Unfortunately, the right way to do this is not obvious from the<br>
>>> Q Monad’s interface[1]. The monad provides `qGetQ` and `qPutQ` methods to<br>
>>> provide a place to store state across quotes, but unfortunately this state<br>
>>> is local to each module. It is desirable from a usability perspective to be<br>
>>> able to reuse PADS declarations across modules, but in the particular case<br>
>>> of PADS the problem is actually worse than that. PADS ships with a standard<br>
>>> library module which uses PADS to define several of the core types required<br>
>>> to be productive, so without the ability to do type checking across modules<br>
>>> the use of this standard library becomes impossible. There are two solutions<br>
>>> to the problem that we have considered.<br>
>>><br>
>>><br>
>>> We can generate metadata about each type as it is defined and emit a top<br>
>>> level declaration which contains this metadata.<br>
>>><br>
>>> This clutters the global namespace.<br>
>>><br>
>>> It lets you examine the metadata for each type easily in `ghci` which<br>
>>> leads to a nice debugging workflow.<br>
>>><br>
>>> If you want to perform any typechecks or other calculations based on the<br>
>>> metadata, they must happen after generated code is spliced in.<br>
>>><br>
>>> This means you lose a lot of type safety because everything must be<br>
>>> represented as an `Exp` (even with typed template haskell there is no way to<br>
>>> get a type for an `Exp` of the form `VarE <<name of metadata>>`)<br>
>>><br>
>>> It becomes impossible to report type errors at compile time. This is a<br>
>>> dealbreaker because otherwise, what is the point?<br>
>>><br>
>>> Using `unsafePerformIO` to create an IORef and then using the Q Monand’s<br>
>>> `qRunIO` function to access the state cell.<br>
>>><br>
>>> This works smoothly across modules<br>
>>><br>
>>> You get type safety back because everything happens in the Q Monad. You<br>
>>> don’t have to generate code in order to get at the values.<br>
>>><br>
>>> It uses `unsafePerformIO` and `qRunIO` so you have to worry about how<br>
>>> often everything gets run.<br>
>>><br>
>>> It seems like it should be safe with a {-# NONINLINE #-} pragma for the<br>
>>> code which creates the IORef.<br>
>>><br>
>>> The IORef is hidden, and no one else should be able to modify it.<br>
>>><br>
>>> Adding stuff to a `Data.Map.Strict` (the environment implementation we<br>
>>> are using) is idempotent, so the quote code getting run multiple times<br>
>>> should not be an issue.<br>
>>><br>
>>><br>
>>> We have two main questions based on this.<br>
>>><br>
>>> Is the IO (ab)use outlined above really as safe as we think it is?<br>
>>><br>
>>> Given that environments are such a common requirement in compiling<br>
>>> programming languages, and the goal of quasi quotation is allowing easy<br>
>>> creation of EDSLs for Haskell, does it make sense to provide some state<br>
>>> mechanism for the Q monad which is not restricted by modules.<br>
>>><br>
>>><br>
>>><br>
>>> [1]:<br>
>>> <a href="https://hackage.haskell.org/package/template-haskell-2.11.1.0/docs/Language-Haskell-TH-Syntax.html" rel="noreferrer" target="_blank">https://hackage.haskell.org/<wbr>package/template-haskell-2.11.<wbr>1.0/docs/Language-Haskell-TH-<wbr>Syntax.html</a><br>
>>><br>
>>><br>
>>> Thanks,<br>
>>><br>
>>> Ethan Pailes<br>
>>><br>
>>> ______________________________<wbr>_________________<br>
>>> Libraries mailing list<br>
>>> <a href="mailto:Libraries@haskell.org">Libraries@haskell.org</a><br>
>>> <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-<wbr>bin/mailman/listinfo/libraries</a><br>
><br>
><br>
</div></div></blockquote></div><br></div>