The module I put together already has everything I&#39;d need to do it in terms of an IntMap with much less work than that -- the generic MonadArray type class has implementations both in terms of ST and in terms of an IntMap already.&nbsp; Only three changes in the Heap implementation would be needed: two changes from runArrayT_ 16 to evalIntMapT, and one change of ArrayT to IntMapT.&nbsp; (Here ArrayT is backed by an STT transformer.)<br>
<br>newtype HeapT e m a = HeapT {execHeapT :: ArrayT e (StateT Int m) a} deriving (Monad, MonadReader r, MonadST s, MonadWriter w, MonadFix, MonadIO)<br><br>-- | Runs an &#39;HeapT&#39; transformer starting with an empty heap.<br>
runHeapT :: (Monad m, Ord e) =&gt; HeapT e m a -&gt; m a<br>runHeapT m = evalStateT (runArrayT_ 16 (execHeapT m)) 0<br><br>But I&#39;m still not entirely convinced that the original STT monad with all its illegal behavior, hidden from the user, couldn&#39;t be used internally by HeapT without exposing non-referential-transparency -- I&#39;m still thinking on that problem.&nbsp; (Perhaps it&#39;d be useful to ask, how would this purely functional implementation of HeapT behave when used as a drop-in replacement for the STT-backed HeapT?)<br>
<br>Originally I said that I was inferring that the problem with an ST transformer was that it allowed access to mutable references.&nbsp; If that&#39;s true, can a priority queue be used to simulate an STRef?&nbsp; If so, wouldn&#39;t that imply (rather elegantly, in fact) that an STT-backed heap transformer would violate referential transparency.&nbsp; (Would the single-threaded array transformer backing HeapT fail in that fashion as well?)<br>
<br clear="all">Louis Wasserman<br><a href="mailto:wasserman.louis@gmail.com">wasserman.louis@gmail.com</a><br>
<br><br><div class="gmail_quote">On Sun, Feb 15, 2009 at 6:15 PM, Ryan Ingram <span dir="ltr">&lt;<a href="mailto:ryani.spam@gmail.com">ryani.spam@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
You can roll your own pure STT monad, at the cost of performance:<br>
<br>
-- Do not export any of these constructors, just the types STT and STTRef.<br>
data W = forall a. W !a<br>
data Heap s = Heap !Int !(IntMap W)<br>
newtype STT s m a = STT (StateT (Heap s) m a) deriving (Monad,<br>
MonadTrans, MonadIO, insert other stuff here, but not MonadState)<br>
newtype STTRef s a = Ref Int<br>
<br>
liftState :: (MonadState s m) =&gt; (s -&gt; (a,s)) -&gt; m a<br>
liftState f = do<br>
 &nbsp; &nbsp;(a, s&#39;) &lt;- liftM f get<br>
 &nbsp; &nbsp;put s&#39;<br>
 &nbsp; &nbsp;return a<br>
<br>
newSTTRef :: forall s m a. a -&gt; STT s m a<br>
newSTTRef a = STT $ liftState go where<br>
 &nbsp; &nbsp;go (Heap sz m) = (Ref sz, Heap (sz+1) (insert sz (W a) m)<br>
<br>
readSTTRef :: forall s m a. STTRef s a -&gt; STT s m a<br>
readSTTRef (Ref n) = STT $ liftM go get where<br>
 &nbsp; &nbsp;go (Heap _ m) = case lookup n m of<br>
 &nbsp; &nbsp; &nbsp; &nbsp;Just (~(W a)) -&gt; unsafeCoerce a<br>
 &nbsp; &nbsp; &nbsp; &nbsp;_ -&gt; error &quot;impossible: map lookup failed.&quot;<br>
<br>
writeSTTRef :: forall s m a. STTRef s a -&gt; a -&gt; STT s m ()<br>
writeSTTRef (Ref n) a = STT $ modify go where<br>
 &nbsp; &nbsp;go (Heap sz m) = Heap sz (insert n (W a) m)<br>
<br>
-- forall s. here makes unsafeCoerce in readSTTRef safe. &nbsp;Otherwise<br>
references could escape and break unsafeCoerce.<br>
runSTT :: (forall s. STT s m a) -&gt; m a<br>
runSTT (STT m) = evalStateT m (Heap 0 empty)<br>
<br>
instance (MonadState s m) =&gt; MonadState s (STT st m) where<br>
 &nbsp; &nbsp;get = lift get<br>
 &nbsp; &nbsp;put = lift . put<br>
 &nbsp; &nbsp;modify = lift . modify<br>
<br>
Unfortunately, you lose garbage collection on referenced data since<br>
it&#39;s all stored in an IntMap. &nbsp;Is there a way to solve this problem,<br>
perhaps using some form of weak reference? &nbsp;Ideally you&#39;d like to be<br>
able to find that all references to a particular Ref have been GC&#39;d so<br>
that you can reuse that Ref index. &nbsp;Otherwise eventually the IntMap<br>
will fill up if you keep allocating references and throwing them away.<br>
<br>
 &nbsp; -- ryan<br>
<br>
2009/2/15 Louis Wasserman &lt;<a href="mailto:wasserman.louis@gmail.com">wasserman.louis@gmail.com</a>&gt;:<br>
<div><div></div><div class="Wj3C7c">&gt; Well, it makes me sad, I guess. &nbsp;pqueue-mtl provides an array-backed heap<br>
&gt; monad transformer that is supposed to keep its own ST thread, if only for<br>
&gt; the sake of retaining a purely functional interface without any externally<br>
&gt; visible forall&#39;d types, which is perfectly fine in most cases, but I&#39;d have<br>
&gt; to think about whether or not it&#39;d remain referentially transparent if the<br>
&gt; ST thread were only visible to a very tightly encapsulated set of commands<br>
&gt; (i.e. priority queue operations).<br>
&gt;<br>
&gt; Louis Wasserman<br>
&gt; <a href="mailto:wasserman.louis@gmail.com">wasserman.louis@gmail.com</a><br>
&gt;<br>
&gt;<br>
&gt; On Sun, Feb 15, 2009 at 5:33 PM, Henning Thielemann<br>
&gt; &lt;<a href="mailto:lemming@henning-thielemann.de">lemming@henning-thielemann.de</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt; On Sun, 15 Feb 2009, Louis Wasserman wrote:<br>
&gt;&gt;<br>
&gt;&gt;&gt; I follow. &nbsp;The primary issue, I&#39;m sort of wildly inferring, is that use<br>
&gt;&gt;&gt; of STT -- despite being<br>
&gt;&gt;&gt; pretty much a State monad on the inside -- allows access to things like<br>
&gt;&gt;&gt; mutable references?<br>
&gt;&gt;<br>
&gt;&gt; I assume that ST must always be the most inner monad, like IO. Is this a<br>
&gt;&gt; problem in an application?<br>
&gt;<br>
</div></div>&gt; _______________________________________________<br>
&gt; Haskell-Cafe mailing list<br>
&gt; <a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
&gt; <a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
&gt;<br>
&gt;<br>
</blockquote></div><br>