<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
Hi Chris,<br>
<br>
You are right. The implementation is totally dodgy! In fact, Pipes
already hasĀ
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<tt>fromHandle</tt> 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 <tt>withCSV</tt> with a action that is *not*
in the IO monad.<br>
<br>
Dimitri<br>
<br>
<div class="moz-cite-prefix">On 10/27/15 5:52 PM, Chris Wong wrote:<br>
</div>
<blockquote
cite="mid:CANQO64+cKAx-oamyOYz+pExJFnNUMNCOtLV_E2BO1Ffoaa4pjA@mail.gmail.com"
type="cite">
<pre wrap="">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] <a class="moz-txt-link-freetext" href="https://hackage.haskell.org/package/pipes-safe-2.2.3/docs/Pipes-Safe.html">https://hackage.haskell.org/package/pipes-safe-2.2.3/docs/Pipes-Safe.html</a>
On Wed, Oct 28, 2015 at 12:25 PM, Dimitri DeFigueiredo
<a class="moz-txt-link-rfc2396E" href="mailto:defigueiredo@ucdavis.edu"><defigueiredo@ucdavis.edu></a> wrote:
</pre>
<blockquote type="cite">
<pre wrap="">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 here
<a class="moz-txt-link-freetext" href="https://gist.github.com/dimitri-xyz/f1f5bd4c0f7f2bf85379">https://gist.github.com/dimitri-xyz/f1f5bd4c0f7f2bf85379</a>
On 10/26/15 10:47 AM, Kim-Ee Yeoh wrote:
On Mon, Oct 26, 2015 at 11:36 PM, Dimitri DeFigueiredo
<a class="moz-txt-link-rfc2396E" href="mailto:defigueiredo@ucdavis.edu"><defigueiredo@ucdavis.edu></a> wrote:
</pre>
<blockquote type="cite">
<pre wrap="">
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).
</pre>
</blockquote>
<pre wrap="">
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
<a class="moz-txt-link-abbreviated" href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a>
<a class="moz-txt-link-freetext" href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a>
</pre>
</blockquote>
<pre wrap="">
</pre>
</blockquote>
<br>
</body>
</html>