I apologize for the delay. Right now I'm going through a large backlog of things that I delayed while completing my dissertation.

I will comment inline below:

On 11/28/2013 2:06 PM, Tyson Whitehead wrote:
I've been implementing the pipes internals based on their description to learn more about them (nice framework BTW). I'm currently working through the pipe-safe routines and have run into an issue where I can't see how liftMask is correct as currently implemented

http://lpaste.net/96356

In more details, in something like (runEffect $ mask examplep), where example is

examplep :: (MonadIO m, MonadCatch m) => (forall q. Proxy a' a b' () m q -> Proxy a' a b' () m q) -> Proxy a' a b' () m ()
  examplep unmask = do
    unmask do
      liftIO $ putStrLn "IO Action 1"
      yield ()
      liftIO $ putStrLn "IO Action 2"
      return ()

mask returns multiple IO actions that are run in runEffect. This means that each lifted IO operation will potentially have it's own unique unmask operation. The mask code, however, captures the first unmask operation in a closure and then uses it for all subsequent operations (i.e., "IO Action 2" is unmasked using "IO Action 1"'s unmask operation instead of its own).

That is, in (runEffect $ mask examplep)

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. 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.


Am I missing something here or is this a bug?

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].

--
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