I finally was able to track a weird bug I was having down to the (at least to me) surprising interaction between mask and timeout:
import System.Timeout
import Control.Exception
ack :: Int -> Int -> Int
ack m n | m == 0, n >= 0 = n + 1
| m > 0, n == 0 = ack (m - 1) 1
| m > 0, n > 0 = ack (m - 1) (ack m (n - 1))
tryack :: Int -> Int -> IO (Maybe Int)
tryack m n = timeout 100000 {- uS -} $ evaluate $ ack m n
main :: IO ()
main = do
a <- tryack 3 11
print a -- Nothing
b <- mask_ $ tryack 3 11
print b -- Just 16381 after a few seconds
This strikes me as a rather “non-compositional” interaction, as it means that if a library internally uses timeout, an externally applied mask somewhere up the call-chain may cause the library to malfunction.
So is this a (known) deficiency in the implementation of timeout or is it intentional?
What does
mask_do?And what does
timeoutdo?So…
mask_is preventingtimeoutfrom delivering its exceptions. That’s just how it is.You just can’t use
maskand havetimeoutwork.Perhaps a better approach would be to use a handler to catch anything but the exception that
timeoutuses?