[Haskell-cafe] best practice for lifting of IO and could lifting
defigueiredo at ucdavis.edu
Wed Oct 28 00:02:19 UTC 2015
You are right. The implementation is totally dodgy! In fact, Pipes
already has fromHandle which does this properly. I'm just trying to come
up with an example of an IO action that takes another IO action as a
parameter and what to do about using that with a monad transformer such
as pipes. My focus is what to do when you need to use an action such as
withCSV with a action that is *not* in the IO monad.
On 10/27/15 5:52 PM, Chris Wong wrote:
> Hi Dimitri,
> The implementation of `withCSVLifted` looks dodgy to me. If a
> downstream consumer terminates early, then the file will never get
> For pipes, the standard solution to resource management is the
> pipes-safe package. It handles early termination and IO exceptions
> automatically. The example in the docs should fit your use case pretty
>  https://hackage.haskell.org/package/pipes-safe-2.2.3/docs/Pipes-Safe.html
> On Wed, Oct 28, 2015 at 12:25 PM, Dimitri DeFigueiredo
> <defigueiredo at ucdavis.edu> wrote:
>> Here's a final pipes example then. I don't think there's a way to fix the
>> problem as Oleg proposed because pipes are monad transformers by design.
>> The Pipe monad transformer augments the base monad with two operations:
>> - await: gets a result from an upstream pipe
>> - yield: sends a result to a downstream pipe
>> I have a producer (which is a pipe that can only 'yield') that produces the
>> lines of the .CSV file as Strings and returns () when done:
>> getFileContentsLifted :: Producer String IO ()
>> getFileContentsLifted = withCSVLifted "data.csv" myReadFile
>> myReadFile :: Handle -> Producer String IO ()
>> myReadFile handle = do
>> eof <- lift $ hIsEOF handle
>> unless eof $ do
>> str <- lift $ hGetLine handle
>> yield str
>> myReadFile handle
>> I then have a simple pipeline that reads each line and prints it twice:
>> lineDoubler :: Pipe String String IO ()
>> lineDoubler = forever $ do
>> s <- await
>> yield s
>> yield s
>> main = do
>> runEffect $ getFileContentsLifted >-> lineDoubler >-> stdoutLn
>> The problem as before is that this code does not work with the original
>> version of withCSV:
>> withCSV :: FilePath -> (Handle -> IO r) -> IO r
>> withCSV path action = do
>> putStrLn "opening file"
>> h <- openFile path ReadMode
>> r <- action h
>> hClose h
>> putStrLn "file closed"
>> return r
>> only with the lifted (i.e. generalized) one.
>> withCSVLifted :: MonadIO mIO => FilePath -> (Handle -> mIO r) -> mIO r
>> withCSVLifted path action = do
>> liftIO $ putStrLn "opening file"
>> h <- liftIO $ openFile path ReadMode
>> r <- action h
>> liftIO $ hClose h
>> liftIO $ putStrLn "file closed"
>> return r
>> And I have the same question: Should I always "generalize" my monadic
>> actions that take callbacks as parameters?
>> I hope this version is still clear. Thanks for everyone for their input. I
>> thought this was an easier problem than it now appears to be.
>> PS. Full code is here
>> On 10/26/15 10:47 AM, Kim-Ee Yeoh wrote:
>> On Mon, Oct 26, 2015 at 11:36 PM, Dimitri DeFigueiredo
>> <defigueiredo at ucdavis.edu> wrote:
>>> I might have over simplified the problem by using ReaderT in my example.
>>> In my original problem this role is played by the Pipes library (and instead
>>> of using 'ask', I wanted to 'yield' control to a downstream pipe).
>> Is there a way you could introduce just enough complexity to allow Oleg
>> another stab?
>> Also, there's always the fallback of showing your Pipes-based code although
>> that library doesn't enjoy universal familiarity.
>> -- Kim-Ee
>> Haskell-Cafe mailing list
>> Haskell-Cafe at haskell.org
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Haskell-Cafe