atomicModifyMutVar2

David Feuer david.feuer at gmail.com
Thu Oct 17 01:31:14 UTC 2019


Well, you basically need two primops. In approximate terms,

atomGen :: (a -> q) -> (q -> a) -> IORef a -> IO (a, q)
atomSel :: (a -> q) -> Int -> IORef a -> IO (a, q)

atomGen is rewritten to atomSel whenever the (q -> a) function is actually
a selector function, in which case it is represented by the field position.
Only atomGen would be considered "public", as the true type of atomSel
can't be expressed.

On Wed, Oct 16, 2019, 9:07 PM Carter Schonwald <carter.schonwald at gmail.com>
wrote:

>  how do you type check it / what type would you plausibly given it thats
> wired into very innards of ghc type system implementation? (by which i mean
> that most / all primops currently are pretty conservative in terms of the
> range of ghc type system features they use)
>
>
> On Wed, Oct 16, 2019 at 1:51 PM David Feuer <david.feuer at gmail.com> wrote:
>
>> What do you think about the version that takes a function as an argument,
>> and is optimized for the case where that's a selector? That really feels
>> like the platonic ideal here.
>>
>> On Mon, Oct 14, 2019, 6:35 PM Simon Peyton Jones <simonpj at microsoft.com>
>> wrote:
>>
>>> OK.   I propose:
>>>
>>>
>>>
>>>    - To give atomicModieyMutVarOf# its proper type, with a  pair, as in
>>>    the proposal.
>>>    - To do that I’ll fiddle with genprimopcode, to allow it to parse
>>>    tuples as well as unboxed tuples; not hard.
>>>    - This would disallow all this stuff about “any type that has a
>>>    first field looking like a”, restricting to pairs alone.  This didn’t form
>>>    part of the proposal, and was never documented.
>>>    - Add a bit more clarity to the documentation, so it’d clear what
>>>    must be forced.
>>>
>>>
>>>
>>> Any objections?
>>>
>>>
>>>
>>> Simon
>>>
>>>
>>>
>>> *From:* David Feuer <david.feuer at gmail.com>
>>> *Sent:* 12 October 2019 00:00
>>> *To:* Simon Peyton Jones <simonpj at microsoft.com>
>>> *Cc:* ghc-devs <ghc-devs at haskell.org>
>>> *Subject:* Re: atomicModifyMutVar2
>>>
>>>
>>>
>>> I don't remember what documentation, if any, it has. You're right that
>>> taking advantage of it is potentially risky. Here's what I think we really
>>> want:
>>>
>>>
>>>
>>> atomicModifyMutVarQ# :: MutVar# s a -> (q -> a) -> (a -> q)  -> State#
>>> s -> (# State# s, a, q #)
>>>
>>>
>>>
>>> where there's a special rule that (q -> a) is "obviously" a selector
>>> that selects a pointer.
>>>
>>> On Fri, Oct 11, 2019, 12:56 PM Simon Peyton Jones <simonpj at microsoft.com>
>>> wrote:
>>>
>>> The result doesn't have to be a pair. It can be a tuple of any size at
>>> all. Indeed, it can even be an arbitrary record type whose first pointer
>>> field has the appropriate type.
>>>
>>>
>>>
>>> I think that is 100.0% undocumented, in the code, or in the proposal.
>>> Are you sure this is a settled consensus among the interested parties?
>>>
>>>
>>>
>>> Adopting it would impose new invariants on the representation of values
>>> in GHC that I am deeply reluctant to impose.  I would much much prefer to
>>> stick with the pair that is (somewhat) documented.
>>>
>>>
>>>
>>> About pair vs Unit, yes, I can see (just) your point about why a pair
>>> might be useful.  Here’s a better example:
>>>
>>>
>>>
>>> Suppose mv :: MutVar# Int
>>>
>>>
>>>
>>> atomicModifyMutVar2# mv $ \a ->
>>>
>>>   let foo = f a
>>>
>>>   in (g foo, foo)
>>>
>>>
>>>
>>> Now, if f is expensive, *and g is not invertible*, then sharing foo
>>> might be useful.  It’s hard to think of a credible example, though.
>>> Regardless, we should document it.
>>>
>>>
>>>
>>> Simon
>>>
>>>
>>>
>>> *From:* David Feuer <david.feuer at gmail.com>
>>> *Sent:* 11 October 2019 17:03
>>> *To:* Simon Peyton Jones <simonpj at microsoft.com>
>>> *Cc:* ghc-devs <ghc-devs at haskell.org>
>>> *Subject:* Re: atomicModifyMutVar2
>>>
>>>
>>>
>>> On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones <simonpj at microsoft.com>
>>> wrote:
>>>
>>> David
>>>
>>> I’m deeply puzzled atomicModifyMutVar2#.  I have read the proposal
>>> <https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fghc-proposals%2Fghc-proposals%2Fblob%2Fmaster%2Fproposals%2F0149-atomicModifyMutVar.rst&data=02%7C01%7Csimonpj%40microsoft.com%7C0b9a79c810d7453ce16008d74e9ebfc1%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637064316038353079&sdata=LGyYiZC9b9g3lZpzTdvQgyEwKCaEsIzFDBcacVE2N5M%3D&reserved=0>,
>>> and the comments in primops.txt.pp (reproduced below).
>>> Question 1
>>>
>>> I think the “real” type of atomicModifyMutVar2 is
>>>
>>> atomicModifyMutVar2# :: MutVar# s a
>>>
>>>                      -> (a -> (a,b))
>>>
>>>                      -> State# s
>>>
>>>                      -> (# State# s, a, (a, b) #)
>>>
>>>
>>>
>>> Close, but not quite. The result doesn't have to be a pair. It can be a
>>> tuple of any size at all. Indeed, it can even be an arbitrary record type
>>> whose first pointer field has the appropriate type.
>>>
>>>
>>>
>>> Nowhere is this explicitly stated, but I believe that the intended
>>> semantics of a call
>>>
>>> case (atomicModifyMutVar2# mv f s) of (# s’, x, r #) -> blah
>>>
>>> Then, suppose the old value of the MutVar was ‘*old’*
>>>
>>>    - The primop builds a thunk  *t *= *f old*
>>>    - The new value of the mutable variable is *(fst t)*
>>>    - The result *r* is t
>>>    - The result *x* is *old*
>>>
>>> Question: is that correct?   We should state it explicitly.
>>>
>>> Yes, that sounds right.
>>>
>>> Question 2
>>>
>>> Next question: Why does f have to return a pair?  So far as I can tell,
>>> it’s only so that a client can force it.   The ‘b’ part never seems to play
>>> a useful role.   So we could equally well have had
>>>
>>> atomicModifyMutVar2# :: MutVar# s a
>>>
>>>                      -> (a -> Box a)
>>>
>>>                      -> State# s
>>>
>>>                      -> (# State# s, a, Unit a #)
>>>
>>> where Unit is defined in Data.Tuple
>>>
>>>     data Unit a = Unit a
>>>
>>> Now you can force the result of (f old), just as with a pair.  But the
>>> ‘b’ would no longer complicate matters.
>>>
>>> Question: is the ‘b’ in the pair significant?   Or could we use Unit?
>>>
>>> Yes, it's somewhat significant. You actually can use Unit with the new
>>> primop (it's a tuple of arity 1), so that option is free. But using a pair
>>> gets you a bit more: you can build a thunk that's *shared* between the
>>> value installed in the MutVar and the one returned to the outside. Consider
>>>
>>>
>>>
>>> atomicModifyMutVar2# mv $ \a ->
>>>
>>>   let foo = expensive_computation a
>>>
>>>   in ([3,foo], foo)
>>>
>>> Question 3
>>>
>>> In the comments below you say "but we don't know about pairs here”.
>>> Are you sure?  What stops you importing Data.Tuple into GHC.Prim?   This
>>> fancy footwork is one more complication, if it could be avoided.
>>>
>>> That whole regime came before my time, but since we win a bit by *not*
>>> fixing it, o wouldn't jump on it too quick.
>>>
>>>
>>>
>>> _______________________________________________
>> ghc-devs mailing list
>> ghc-devs at haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-devs/attachments/20191016/e8284cc5/attachment-0001.html>


More information about the ghc-devs mailing list