> On Feb 10, 2020, at 02:18, Simon Marlow <[email protected]> wrote:
>
>> On Mon, 10 Feb 2020 at 08:17, Simon Marlow <[email protected]> wrote:
>>
>> Let me just say "unsafePerformIO" :) You probably want to at least ensure
>> that things don't crash in that case, even if you can't give a sensible
>> semantics to what actually happens. We have a similar situation with
>> unsafeIOToST - we can't tell you exactly what it does in general, except
>> that it doesn't crash (I hope!).
>
> Typo - I meant unsafeIOToSTM here.
I’ve been thinking about this. At first I figured you were probably right, and
I decided I’d switch to a more raiseAsync-like approach. But once I started
trying to implement it, I became less convinced it makes sense.
As its name implies, an AP_STACK is sort of like a saturated application, where
the stack itself is the “function.” Extending the analogy, a continuation would
be a PAP_STACK, since the stack is awaiting a value. This difference is
significant. Suppose you write:
let x = 1 + unsafePerformIO (shift f >>= g) in ...
If you force x, the stack will unwind to the nearest reset. When you unwind
past x’s UPDATE_FRAME, you can’t replace the blackhole with an AP_STACK, since
the captured slice of the stack represents the expression
\m -> 1 + unsafePerformIO (m >>= g)
which is a function, not a thunk. The only logical interpretation of this
situation is that x is a thunk quite like
let y = 1 + error "bang"
except that it doesn’t just abort to the enclosing reset frame when forced, it
actually composes the captured continuation with the upper frames of the
current stack and passes the composed continuation to f to resume computation.
That’s an awful lot of trouble given the resulting semantics is going to be
unpredictable, anyway!
I should be clear that I do not intend shift/reset to have any safe interface
in IO directly. Even if you could make it type safe, it would break all kinds
of code that manages resources using bracket. Rather, I have built a library
that defines a totally separate Eff monad, and that monad uses the primops
directly, wrapped in a safe interface. It isn’t possible for a user to screw
things up using unsafePerformIO because there is no way to call shift from IO
(unless you wrap shift# in IO yourself, but then I think you can be expected to
know what you’re getting yourself into). So without mucking about with
GHC.Exts, you still can’t get segfaults.
Alexis
_______________________________________________
ghc-devs mailing list
[email protected]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs