My application needs to have several resources open during runtime. I am achieving this by mapping over openFile once at the start of the application.
let filePaths = ["/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2"]
fileHandles <- mapM (`openFile` ReadWriteMode) filePaths
This code is not safe as it might work for the first 2 file paths but then throw an exception when opening the 3rd file path. In that case i need to close the first 2 file paths that were opened already so i can exit the function without leaking resources. i have looked at the functions and patterns from Control.Exception but not found anything that helps in this case. I have not looked at ResourceT yet. Does it help in this situation?
I think i am looking for a function signature that is similar to this:
safeMapM:: [a] -> (a -> IO b) -> (b -> IO()) -> [b]
where (b -> IO()) is the clean up function that is called when some exception occurred.
Solutions i could think of that are probably not good:
- wrapping each element in a
Maybe. Exceptions can be catched and result in aNothing. themapMcould always finish and i could check for Nothing/Exception afterwards and then close all successfully opened file handles by theirJust Handle. - using fold instead of map. when an exception at the current element occurs i can close the file handles of all previous elements of the fold and then rethrow the exception to stop the fold from continuing.