1

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.

2
  • 2
    Passing a function and a list of arguments is needed in other languages, when e.g. they are strict or ridden with side-effects. In Haskell, there's no need to do that. If the function is pure, just pass its result (it's not evaluated anyway) as an a; otherwise pass a IO a action as you are doing above (it's not executed until later). Commented Sep 2, 2016 at 13:28
  • Why not pass the result of the function into catchOutput instead of trying to pass the function and its arguments? Commented Sep 3, 2016 at 14:41

1 Answer 1

3

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.
Sign up to request clarification or add additional context in comments.

2 Comments

As I understand it one cannot generate a list where the elements have different types. Thus the usage of Data.Dynamic for the different elements of the argument list.
Yes, you cannot have a list with elements of different types, but I don't see any lists in your code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.