-
Notifications
You must be signed in to change notification settings - Fork 67
Description
I am possibly misunderstanding how generalBracket
works but here is my analysis.
My situation is that I want to take an AVar, do some action on the value, then put a value to the AVar and return the action result. The invariant is that if the AVar was taken then a value must be put to it, and if the AVar was not taken then a value must not be put to it. Taking the AVar must be killable.
This first example makes no attempt at bracketing but demonstrates what should happen on the happy path.
transact ∷ ∀ a b. (a → Aff (Tuple a b)) → AVar a → Aff b
transact f v = do
a ← AVar.take v
Tuple a' b ← f x
AVar.put a' v
pure b
There are several places in which a failure or kill breaks the invariant. Adding brackets, first to deal with taking the AVar must be killable:
transact f v =
generalBracket
(pure unit)
{ killed: \_ _ → pure unit
, failed: \_ _ → pure unit
, completed: …
}
(\_ → AVar.take v)
And now this is stuck. There is no way to return the result from completed
, so there is no way to continue transact
given that taking the AVar succeeded.
In other words, brackets are not nestable. Say they were, however, this is what could be done:
transact f v =
generalBracket (pure unit)
{ killed: \_ _ → pure unit
, failed: \_ _ → pure unit
, completed: \a _ →
generalBracket (pure unit)
{ killed: \_ _ → AVar.put a v
, failed: \_ _ → AVar.put a v
, completed: \(Tuple a' b) _ → invincible (AVar.put a' v $> b)
}
(f a)
}
(\_ → AVar.take v)
This assumes the typing:
generalBracket ∷ ∀ a b c. Aff a → BracketConditions a b c → (a → Aff b) → Aff c
type BracketConditions a b c =
{ killed ∷ Error → a → Aff Unit
, failed ∷ Error → a → Aff Unit
, completed ∷ b → a → Aff c
}
If there is another way to implement this program I just am not seeing it right now.