
John & all, I use HSH in my project where several external programs and Haskell functions need to be piped together: HSH is of great help here. I however came across the situation when one of pipe-connected functions has signature IO (), yet it reads from stdin* and writes to stdout. The documentation mentions "instance ShellCommand (Handle -> Handle -> IO ())" which could be of some help, but in the latest version of HSH on Hackage this instance is commented out. What was the reason of doing that? Is this to be expected in the upcoming versions? Thank you. ---------------------------- * I modelled that by calling getContents, but the actual program will call a foreign library that contains a C function that reads from stdin (that is, FILE *), and that cannot be changed easily. -- Dimitry Golubovsky Anywhere on the Web

Dimitry Golubovsky wrote:
John & all,
I use HSH in my project where several external programs and Haskell functions need to be piped together: HSH is of great help here.
I however came across the situation when one of pipe-connected functions has signature IO (), yet it reads from stdin* and writes to stdout.
The documentation mentions "instance ShellCommand (Handle -> Handle -> IO ())" which could be of some help, but in the latest version of HSH on Hackage this instance is commented out.
What was the reason of doing that? Is this to be expected in the upcoming versions?
Yes; that's due to the new more flexible way of sending data between processes in HSH -- the Channel. You can replace it with a function that can take any Channel, and produce a result as a Channel of one particular sort. In particular, this instance: instance ShellCommand (Channel -> IO Channel) where is the direct replacement for what you were doing. A Channel is generally a String, a lazy ByteString, or a Handle. There are helper functions in HSH.Channel to deal with these: chanAsString, chanAsBSL, and chanToHandle. You can think of the first two as similar to hGetContents. The last will write the channel out literally to a passed-along handle. So, let's say that you wanted to process input as a String, and before you were given a Handle that you used hGetContents on. Now, you will get a Channel, on which you will call chanAsString. It will convert whatever type of Channel you were handed into a String, lazily. Does that make sense?

John,
Thanks for the reply.
In this case, would the body of my function run in a separate thread
via forkProcess (that's what is needed, maybe I didn't make it clear)?
In my previous project, I had to do like this (probably not very
portable, at least requires System.Posix):
========================================================
(fd1, fd2) <- createPipe
hscfd <- fileToFd hscFile
hscpid <- forkProcess $ redirFd fd1 0 $
redirFd fd2 (-1) $
redirFd hscfd 1 $
hsffigMain (fromJust $ gccPath dopt)
(inclDirs dopt) minusD
gccpid <- forkProcess $ redirFd fd2 1 $
executeFile (fromJust $ gccPath dopt)
False
(["-E", "-dD"] ++
minusI ++ minusD ++
[incFile])
Nothing
closeFd hscfd
closeFd fd1
closeFd fd2
gccrt <- getProcessStatus True False gccpid
hscrt <- getProcessStatus True False hscpid
========================================================
where hscpid corresponds to a process that runs a Haskell function
(hsffigMain :: a -> b -> c -> IO ()) defined within the same program,
and gccpid runs an external program (gcc), and they are piped
together. I am trying to avoid writing this mess using HSH.
I'm just trying to find out whether this was already done. If not,
what is the best way to write the above to be integrated into HSH (I'd
be glad to contribute).
Thank you.
On Sat, Jun 13, 2009 at 12:46 AM, John Goerzen
You can replace it with a function that can take any Channel, and produce a result as a Channel of one particular sort. In particular, this instance:
instance ShellCommand (Channel -> IO Channel) where
-- Dimitry Golubovsky Anywhere on the Web

Dimitry Golubovsky wrote:
John,
Thanks for the reply.
In this case, would the body of my function run in a separate thread via forkProcess (that's what is needed, maybe I didn't make it clear)?
No; at least not automatically. The idea is that a function that is Channel -> IO Channel should be very similar in concept to a String -> String - processing its input lazily.
In my previous project, I had to do like this (probably not very portable, at least requires System.Posix):
You are aware that HSH has built-in support for executing external commands, right? What is hssfigMain? Is it calling some other program or is it part of the current process? I would suggest that the appropriate idea is to make hsffigMain be some other executable. Then you could just: runIO $ ("hsffigMain", [args, args, ...]) -|- (fromJust $ gccPath dopt, ["-E", "-dD", ...])
where hscpid corresponds to a process that runs a Haskell function (hsffigMain :: a -> b -> c -> IO ()) defined within the same program, and gccpid runs an external program (gcc), and they are piped together. I am trying to avoid writing this mess using HSH.
OK, so I should have read more before starting to reply. But why are you writing to me about HSH if you're trying to *avoid* HSH? I'm confused.
I'm just trying to find out whether this was already done. If not, what is the best way to write the above to be integrated into HSH (I'd be glad to contribute).
Integraing hsffigMain into HSH directly will be difficult because it apparently already has its notions about where its input and output come from; the fact that its return type is IO () implies that its output either goes to stdout or to a file. This type of function cannot be generalized to pipes, because you can only dup2() your stdout once. (You couldn't have two functions like hsffigMain in your pipeline). Your best bet is to make this a separate executable. -- John

On Sat, Jun 13, 2009 at 4:01 PM, John Goerzen
Dimitry Golubovsky wrote:
where hscpid corresponds to a process that runs a Haskell function (hsffigMain :: a -> b -> c -> IO ()) defined within the same program, and gccpid runs an external program (gcc), and they are piped together. I am trying to avoid writing this mess using HSH.
OK, so I should have read more before starting to reply. But why are you writing to me about HSH if you're trying to *avoid* HSH? I'm confused.
I think Dimitry meant, "I'm trying to avoid writing this mess *by* using HSH instead." At least, that's how I read it. Jason

On Sat, Jun 13, 2009 at 05:06:41PM -0700, Jason Dagit wrote:
On Sat, Jun 13, 2009 at 4:01 PM, John Goerzen
wrote: Dimitry Golubovsky wrote:
where hscpid corresponds to a process that runs a Haskell function (hsffigMain :: a -> b -> c -> IO ()) defined within the same program, and gccpid runs an external program (gcc), and they are piped together. I am trying to avoid writing this mess using HSH.
OK, so I should have read more before starting to reply. But why are you writing to me about HSH if you're trying to *avoid* HSH? I'm confused.
I think Dimitry meant, "I'm trying to avoid writing this mess *by* using HSH instead."
At least, that's how I read it.
Ah, that makes more sense. Sorry for the misparsing. -- John

John,
On Sat, Jun 13, 2009 at 7:01 PM, John Goerzen
where hscpid corresponds to a process that runs a Haskell function (hsffigMain :: a -> b -> c -> IO ()) defined within the same program, and gccpid runs an external program (gcc), and they are piped together. I am trying to avoid writing this mess using HSH.
OK, so I should have read more before starting to reply. But why are you writing to me about HSH if you're trying to *avoid* HSH? I'm confused.
Sorry, I should have written "by using"; Jason made the right correction. I thought that forkProcess-based shell commands existed in HSH thus I could avoid all these low-level manipulations with handles that are usually done in C programming.
Integraing hsffigMain into HSH directly will be difficult because it apparently already has its notions about where its input and output come from; the fact that its return type is IO () implies that its output
I'll try to write a wrapper for a forked process inside a Channel -> IO Channel typed function.
Your best bet is to make this a separate executable.
That's not what was intended, but now I see the situation more clearly. Thanks for the explanation. If I get any working code, I'll post a link on the list. -- Dimitry Golubovsky Anywhere on the Web

Dimitry Golubovsky wrote:
I'll try to write a wrapper for a forked process inside a Channel -> IO Channel typed function.
Your best bet would be to start with these instances in HSH.Command: instance ShellCommand (String, [String]) where instance ShellCommand String where and the implementation of genericCommand, which they both call. It is really not that difficult of an implementation, and as of GHC 6.10, no longer even requires the specialized POSIX items. The reason I have two bodies for genericCommand is that if the input channel is a Handle, I can pass it directly as stdin to the child process; otherwise, it is necessary to use chanToHandle to zap it over to stdin. Now, with what you're trying to do, you will probably not be able to get away without using the POSIX stuff though, since you have to dup2() stdin/stdout. I still recommend splitting this into multiple executables. With your approach, the stdin and stdout of your main executable will be messed up forever. This can and does lead to unforseen consequences. -- John
participants (3)
-
Dimitry Golubovsky
-
Jason Dagit
-
John Goerzen