I need to force a net value in an IO monad. I am writing a higher-level interface for C bindings. At the lower level, I have, say newFile functions and freeFile functions. newFile returns some id, an opaque object. I decided on a lower level. You can't do anything about it, but use it to free a file and just figure out something related to that file.
So I (simplified):
execGetter :: FilePath -> TagGetter a -> IO a execGetter path g = do fid <- newFile path -- 'fid' stands for "file id" let x = runGetter g fid freeFile fid return x
This is the initial version of the function. We need to calculate x to freeFile . (The code works if I delete freeFile everything is fine, but I want to free the resource, you know.)
The first attempt (we will use seq for a "forced" evaluation):
execGetter :: FilePath -> TagGetter a -> IO a execGetter path g = do fid <- newFile path let x = runGetter g fid x `seq` freeFile fid return x
Segmentation error. Go straight to the seq documentation:
The value of seq ab is lower if a is the bottom, and otherwise it is b . seq usually introduced to improve performance, avoiding unnecessary laziness.
Note on evaluation order: the expression seq ab does not guarantee that a will be evaluated before b . The only guarantee provided by seq that both a and b will be evaluated before seq returns the cost. In particular, this means that b can be estimated to a . If you need to guarantee a specific evaluation order, you should use the pseq function from the "parallel" package.
A good point, indeed, I have seen people applying for different things about the evaluation procedure in this case. What about pseq ? Should I depend on parallel just because of pseq , hmm ... maybe there is another way.
{-
Segmentation error. Well, this answer does not work in my case. But it offers evaluate , try it too:
Control.Exception (evaluate) Control.Monad (void) execGetter :: FilePath -> TagGetter a -> IO a execGetter path g = do fid <- newFile path let x = runGetter g fid void $ evaluate x freeFile fid return x
Segmentation error. Maybe we should use the value returned by evaluate ?
Control.Exception (evaluate) Control.Monad (void) execGetter :: FilePath -> TagGetter a -> IO a execGetter path g = do fid <- newFile path let x = runGetter g fid x' <- evaluate x freeFile fid return x'
No, a bad idea. Maybe we could chain seq :
execGetter :: FilePath -> TagGetter a -> IO a execGetter path g = do fid <- newFile path let x = runGetter g fid x `seq` freeFile fid `seq` return x
It works. But is it right to do this? Maybe this only works because of some kind of unstable optimization logic? I dont know. If seq binds to the left in this case, then according to this description, both x and freeFile are evaluated when return x returns its value. But then again, which one, x or freeFile is ranked first? Since I am not getting a seg fault, it should be x , but is this result reliable? Do you know how to force x to freeFile correctly?