[Haskell-cafe] best practice for lifting of IO and could lifting

Robin Palotai palotai.robin at gmail.com
Wed Oct 28 11:18:53 UTC 2015


I'm shooting in the dark, but isn't monad-control's liftBaseWith supposed
to address such situations?
https://hackage.haskell.org/package/monad-control-1.0.0.4/docs/Control-Monad-Trans-Control.html#g:3

Robin

Dimitri DeFigueiredo <defigueiredo at ucdavis.edu> ezt írta (időpont: 2015.
okt. 28., Sze, 1:02):

> Hi Chris,
>
> 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.
>
>
> Dimitri
>
>
> 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
> closed.
>
> For pipes, the standard solution to resource management is the
> pipes-safe[1] package. It handles early termination and IO exceptions
> automatically. The example in the docs should fit your use case pretty
> well.
>
> [1] 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> <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
>     where
>         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.
>
> Dimitri
>
> PS. Full code is herehttps://gist.github.com/dimitri-xyz/f1f5bd4c0f7f2bf85379
>
>
> 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> <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 listHaskell-Cafe at haskell.orghttp://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>
>
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20151028/cb7062a8/attachment.html>


More information about the Haskell-Cafe mailing list