David,

Wait!  It gets worse!

Question 4

As I understand it, the idea in the proposal is that you can force the pair 
that comes back from the primop, and that helps you cure a space leak.  Thus


case atomicModifyMutVar2# mv f s of

   (# s’, old, pr #) -> pr `seq`  (# s’, () #)


But it’s extremely easy to write calls that complete defeat such a strategy.  
Your examples and mine below both have this property. Suppose f is

(\x. let v = expensive x in (v,v))
Well, forcing that pair will do nothing at all!  It certainly won’t force v!   
You should probably write

(\x. let v = expensive x in v `seq` (v,v))
or something like that.

Is this right?   At least this should be documented super-clearly.

Simon

From: ghc-devs <ghc-devs-boun...@haskell.org> On Behalf Of Simon Peyton Jones 
via ghc-devs
Sent: 11 October 2019 17:56
To: David Feuer <david.fe...@gmail.com>
Cc: ghc-devs <ghc-devs@haskell.org>
Subject: RE: atomicModifyMutVar2

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.fe...@gmail.com<mailto:david.fe...@gmail.com>>
Sent: 11 October 2019 17:03
To: Simon Peyton Jones <simo...@microsoft.com<mailto:simo...@microsoft.com>>
Cc: ghc-devs <ghc-devs@haskell.org<mailto:ghc-devs@haskell.org>>
Subject: Re: atomicModifyMutVar2

On Fri, Oct 11, 2019, 11:08 AM Simon Peyton Jones 
<simo...@microsoft.com<mailto:simo...@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%7C6f3e8178c339489f52ab08d74e6bfbf6%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637064098002911775&sdata=Acc5vYlorYg%2Bct6Vq2sddv%2B3Q%2BAuPU6yrOKDQLNDZv8%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@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

Reply via email to