Tresia Burger
Tresia Burger

Reputation: 37

Haskell - Pass arbitrary function and argument list as arguments to another function

My main goal is to redirect stderr to a file.

I got hold of the following code snippet...

catchOutput :: IO a -> IO (res, String)
catchOutput f = do
  tmpd <- getTemporaryDirectory
  (tmpf, tmph) <- openTempFile tmpd "haskell_stderr"
  stderr_dup <- hDuplicate stderr
  hDuplicateTo tmph stderr
  hClose tmph
  res <- f
  hDuplicateTo stderr_dup stderr
  str <- readFile tmpf
  removeFile tmpf
  return (res, str)

I hoped to make this more general and pass any function and argument list to catchOutput and get the function result as well as message written to stderr (if any).

I thought that an argument list of type [Data.Dynamic] might work but I failed to retrieve the function result with

res <- Data.List.foldl (f . fromDyn) Nothing $ args

Is this even possible? Help will be greatly appreciated.

Upvotes: 1

Views: 243

Answers (1)

redneb
redneb

Reputation: 23850

There is not reason to use Data.Dynamic. You already know type the return type of f, it's a so you can use just that, i.e.

catchOutput :: IO a -> IO (a, String)

Note though, that there some significant issues with your approach:

  1. By redirecting stderr to a file, this will also affect all other concurrent threads. So you could possibly get unrelated data sent to the temporary file.
  2. If an exception is thrown while stderr is redirected, the original stderr will not be restored. Any operation between the two hDuplicateTo lines (hClose and f in this case) could possibly throw an exception, or the thread may receive an asynchronous exception. For this reason, you have to use something like bracket to make your code exception safe.

Upvotes: 3

Related Questions