On December 21, 2013 09:23:22 AM Gabriel Gonzalez wrote:
> I apologize for the delay.  Right now I'm going through a large backlog 
> of things that I delayed while completing my dissertation.

No problems.  Hopefully you won't mind my even longer delay then.

I still feel that liftMask is wrong, so I wrote a trace program to see for sure 
if it is or isn't (it is).

http://lpaste.net/104220

> On 11/28/2013 2:06 PM, Tyson Whitehead wrote:
> >  1 - each group of IO actions becomes embedded it their own underlying 
> > IO mask operation inside of Proxy's mask,
> >  2 - this underlying IO mask operation stashes the associated IO 
> > unmask function in the IORef inside of Proxy's mask, and
> >  3 - the passed Proxy unmask retrieves this and uses unsafeHoist to 
> > push it through to all further IO actions.
> >
> > The thing I'm having problems with is that, if there are any more 
> > interleaving Request or Respond operations (such as the above yield), 
> > then subsequent IO operations are going to be running in a  different 
> > IO mask operation with a potentially different unmask operation.  I 
> > would think a correct implementation would have to re-read the IORef 
> > for each group of IO actions as the associated IO unmask may have changed.
> 
> It does.  The internal `unmask` function in the implementation of 
> `liftMask` re-reads the `IORef` to retrieve the most recent unmasking 
> function.  This means that every time your `examplep` proxy calls 
> `unmask` it is always getting the latest unmasking function and not just 
> the first one.

That's good as this was my understanding of how it is suppose to work.

> To clarify things further, let's assume that you write something like this:
> 
>      mask $ \restore -> do
>          io1
>          restore io2
>          io3
>          yield ()
>          io4
>          restore io5
>          io6
> 
> This will generate two internal `mask` calls, one of which brackets 
> `io1` through `io3` and one of which brackets `io4` through `io6`. The 
> first call to `restore` will use the unmasking function corresponding to 
> the first internal `mask` call and the second call to `restore` will use 
> the unmasking function corresponding to the second internal `mask` call.

This example is different from mine in that it doesn't have a yield inside the 
unmask call.  This is required to exhibit the bug as my issue was unSafeHoist 
[in the unmask code] pushing the unmask IO operation through to all further IO 
actions [in the unmasked portion of the pipeline including those which will 
operate under a different mask].

We can see this if we run my original example under the trace program (your 
example works fine)

 examplep unmask =
   trace "Proxy  unmask" $
     unmask $ trace "yield (output functions as original two IO calls)" $ yield 
()

 begin Proxy  mask
 begin StateT mask   0
 begin Proxy  unmask
 begin StateT unmask 0
 begin yield (output functions as original two IO calls)
 end   StateT unmask 0
 end   StateT mask   0
 begin StateT mask   1
 begin StateT unmask 0
 end   yield (output functions as original two IO calls)
 end   StateT unmask 0
 begin StateT unmask 0
 end   StateT unmask 0
 end   Proxy  unmask
 end   StateT mask   1
 end   Proxy  mask

(the trace function is now providing the two liftIO putStrLn calls of the 
original).

>From this we can see that unsafeHoist has pushed the "unmask 0" operation 
>corresponding to the "mask 0" operation through the inner "trace "..." $ yield 
>()" proxy resulting in it being used both before and after the yield despite 
>the fact that after the yield we have transitioned to being inside a "mask 1" 
>operation.

Cheers!  -Tyson

-- 
You received this message because you are subscribed to the Google Groups 
"Haskell Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].

Reply via email to