<div dir="ltr"><div>I too am struggling to find a scenario in which this causes something to</div><div>go wrong. Ending up with only one block instead of two copies of it</div><div>seems like it could only be a problem, as Edward says, "if you were</div><div>planning to use these blocks as separate allocation buffers for</div><div>subsequent modifications". But, mutable byte arrays allocated by</div><div>newByteArray# cannot escape runST, so I don't see how this could happen.</div><div>Well, I guess if you returned a frozen array, and then you thawed it</div><div>for subsequent modification outside of runST, that would be problematic,</div><div>but CSE already makes that unsafe, even without involving compact</div><div>regions. It's good to know that, for my purposes, I'm in the clear, but</div><div>I would also like to hear from Edward clarifying the original statement.</div><div><br></div><div>-Andrew Martin</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Jun 19, 2017 at 4:41 AM, David Feuer <span dir="ltr"><<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto">Can you explain how things could go wrong in ST, perhaps with an example? It's hard to see the potential problem.</div><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="h5">On Jun 18, 2017 11:49 PM, "Edward Z. Yang" <<a href="mailto:ezyang@mit.edu" target="_blank">ezyang@mit.edu</a>> wrote:<br type="attribution"></div></div><blockquote class="m_-6098545916430014851quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5">There are two senses of referential transparency here which should be<br>
considered. First is whether or not you will get the same value results<br>
if you use the compact functionality in ST. Here, the answer is yes.<br>
Compact normal form has very trivial semantics in this domain, and<br>
it would have been OK even to make compact normal forms be pure<br>
functions.<br>
<br>
Second is whether or not the performance characteristics are preserved.<br>
Here, the situation is different. Most notably, pure expressions and<br>
invocations of the same runST block may be commoned up (via an<br>
optimization pass like CSE.) In that case, what was previously two<br>
separate compact blocks may be commoned up into a single one. This<br>
could be disaster if you were planning to use these blocks as separate<br>
allocation buffers for subsequent modifications.<br>
<br>
This motivated specializing compact to IO. It won't segfault if you<br>
put it in ST, but the performance characteristics might change.<br>
<br>
Edward<br>
<br>
Excerpts from Andrew Martin's message of 2017-06-18 10:24:09 -0400:<br>
</div></div><div class="m_-6098545916430014851elided-text"><div><div class="h5">> In the primops file where the compact normal form functions are<br>
> documented (<a href="https://github.com/ghc/ghc/blob/adcd1c62b6d372f100ccf1d5d7cd94f79aaac194/compiler/prelude/primops.txt.pp#L2487" rel="noreferrer" target="_blank">https://github.com/ghc/ghc/bl<wbr>ob/adcd1c62b6d372f100ccf1d5d7c<wbr>d94f79aaac194/compiler/<wbr>prelude/primops.txt.pp#L2487</a>),<br>
> I noticed that all of the functions have type signatures that constrain<br>
> them to only being used in IO. For example:<br>
><br>
> compactAdd# :: Compact# -> a -> State# RealWorld -> (# State# RealWorld, a #)<br>
><br>
> I would like to know if generalizing these to allow them to work in ST would<br>
> be sound. That is, changing the type signature to:<br>
><br>
> compactAdd# :: Compact# -> a -> State# s -> (# State# s, a #)<br>
><br>
> I'm not requesting that this change actually be made. I only want to<br>
> know if using unsafeCoerce to create the second function for my own<br>
> project would actually be sound.<br>
><br>
> For those interested in knowing why I want this, it's because there are<br>
> situation where I'm interested in building up a giant structure in a<br>
> compact region, but in a way that doesn't actually require IO. I think<br>
> it's a pity to have to use a type signature with IO and then call<br>
> unsafePerformIO at the end instead of using the more constrained ST,<br>
> and runST, which makes it clear that I'm not doing anything observable<br>
> form the outside.<br>
><br>
> As a minor bonus, the ST version of the Compact data type shouldn't need<br>
> the lock that the IO version does, since concurrent calls to compactAdd<br>
> are not possible.<br>
><br>
> -Andrew Martin<br>
><br></div></div>
______________________________<wbr>_________________<br>
Libraries mailing list<br>
<a href="mailto:Libraries@haskell.org" target="_blank">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-bi<wbr>n/mailman/listinfo/libraries</a><br>
</div></blockquote></div><br></div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">-Andrew Thaddeus Martin</div>
</div>