Возможны ли исключения между восстановлением и маской?

Предположим, что у меня есть код, написанный так:

import Control.Exception (bracketOnError, finally, mask)
import Client (acquireB, releaseB, doStuff) -- theoretical
import MyStuff (preliminary, doMoreStuff) -- theoretical

clientAction = bracketOnError acquireB releaseB $ \b ->
  doStuff b
  return (b, releaseB b)

myAction = mask $ \restore ->
  a <- preliminary
  (thing, releaseThing) <- restore clientAction
  doMoreStuff a thing `finally` releaseThing

Мне нужно сделать некоторые вещи preliminary, мой клиент приобретает b, а затем должен doStuff с b, а затем я должен doMoreStuff с b. И b должен быть выпущен, даже если возникает асинхронное исключение. Но я не знаю, как выпустить b, поэтому мой клиент говорит мне, как это сделать. Написанный таким образом, мы оба готовы выпустить b, если исключение происходит во время "нашего" кода.

Мой вопрос в следующем: возможно ли, когда исключение async вызывает releaseB не выполняться? В частности, существует ли разрыв между "моим кодом" и "кодом моего клиента", в котором может сжиматься исключение async? Позвольте мне вставить clientAction и bracketOnException, чтобы объяснить.

myAction = mask $ \restore -> do
  a <- preliminary
  (thing, releaseThing) <- restore $ mask $ \restore2 -> do
    b <- acquireB
    restore2 (doStuff b >> return (b, releaseB b))
      `onException` releaseB b
  doMoreStuff a thing `finally` releaseThing

Конкуренция такова: есть ли здесь момент здесь

... restore $ mask ...

Правильно, когда клиент mask снят, но до конца моего restore, окружающего его, где исключение может прокрасться через?

Ответ 1

Да, в GHC, когда возникает маскама, мы с нетерпением проверяем блокированные исключения и поднимаем их.