Fork-fragile reader-like operations in Haskell

Following up from Haskell's missing mutable reference type and A reference implementation of IOScopedRef comes the final instalment in the series:

4 Likes

I didn’t know why this wasn’t the first article in the series! The other two articles make a lot more sense with the context from this one.

Making IORefs with unsafePerformIO like that needs a NOINLINE pragma for it to be safe.

Shouldn’t

    -- Restore the original value of the state
    (writeIORef ambientState orig)
    body

Be

    body
    -- Restore the original value of the state
    (writeIORef ambientState orig)

No, the bracket family of functions have the arguments in the following order:

bracket setup cleanup body

-- or in other words
bracket before after middle
1 Like

Yeah, that is somewhat surprising. I guess it makes sense for partial application.

1 Like

Good feedback, thanks! The literal answer is because I wrote them in that order. That was because I thought they were each self-explanatory but I got feedback that they needed more motivation. Of course, that means I probably should have published them in the reverse order to give readers an easier on ramp. If I get time I’ll rework them so that the motivation comes first.

Yeah, thanks, that would make the example more realistic. Added it here: Make ambientState more realistic by adding NOINLINE · tomjaguarpaw/H2@99d9fda · GitHub

The hs-opentelemetry example is good. The current behaviour is, IMO, utterly unusable for any application that uses concurrency to a significant degree.

The way we’ve solved this at CircuitHub is that we use Effectful, which already implements the correct thread-scoped state behaviour for its own state, provided you use its concurrency wrappers (which we do). So we wrote an effect that tracks the hs-opentelemetry Context inside the effect data, instead of in thread-local storage. That works pretty much perfectly.

Which suggests to me that effectful itself would likely benefit from a thread-and-children-scoped-ioref primitive. However - if you dig into effectful you will find that it actually offers quite the array of options for how its environment should be cloned in various different situations. Perhaps effectful needs this because it’s trying to be quite a general framework, but it’s interesting to think about.

4 Likes

One of the reasons is that it clones not only locally mutable state (like IOScopedRef/Reader) but also generally mutable state like IORef/State).