
I've found this example. counter :: IO Int counter = unsafePerformIO $ newIORef 0 getUnique :: IO Int getUnique = atomicModifyIORef counter $ \x -> let y = x + 1 in (y, y) Which I ran, and I know works in as much as calling getUnique multiple times results in an incremented value. I have two things I'm failing to see about it. 1) Why doesn't counter return a newIORef with value 0, every time getUnique is called there by producing a value of 1 no matter how often getUnique is called? Is this this because it returns an IORef so counter just becomes bound to the value it first returns and it's not evaluated again and the IORef is just returned, or something else? 2) Why does the lambda return a tuple and why does the example return the same value in both positions i.e. (y,y)? The only thing I could think of is because the name has "atomic" that the values in the tuple is being used for some sort of compare and swap,CAS. P.S I didn't find http://hackage.haskell.org/package/base-4.6.0.1/docs/Data-IORef.html enlightening on the matter and I know that example is not great because the atomicModifyIORef is lazy so could lead to stackoverflow as that doc. page says... Thanks

On Mon, Jan 6, 2014 at 9:33 PM, Courtney Robinson
I've found this example.
An example of something you should not do; it is very fragile. Most notably, if the compiler decides to inline counter then you no longer have a single IORef. (It will work in ghci/runhaskell, which does not have an optimizer.) I have two things I'm failing to see about it.
1) Why doesn't counter return a newIORef with value 0, every time getUnique is called there by producing a value of 1 no matter how often getUnique is called? Is this this because it returns an IORef so counter just becomes bound to the value it first returns and it's not evaluated again and the IORef is just returned, or something else?
Anything given a name and no parameters (and not polymorphic; see the monomorphism restriction) is potentially shared. The unsafePerformIO would be run only once and its result remembered and shared between all uses --- if you're lucky. The compiler is allowed to do anything it wants as long as it would have the same behavior; but because you hid an effect behind unsafePerformIO, thereby telling the compiler that it is a pure value that it is free to remember or recompute as it sees fit, the compiler's idea of what constitutes "the same behavior" is likely to be different from yours. 2) Why does the lambda return a tuple and why does the example return the
same value in both positions i.e. (y,y)? The only thing I could think of is because the name has "atomic" that the values in the tuple is being used for some sort of compare and swap,CAS.
One value is the return value of atomicModifyIORef; the other is the new value to be stored. You could think of this as the Haskell version of the preincrement/postincrement operators in some languages. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

On Mon, Jan 6, 2014 at 10:15 PM, Courtney Robinson
On Tue, Jan 7, 2014 at 3:03 AM, Brandon Allbery
wrote: behind
Oh I see, thanks for the info. really helpful. It brings about another question now.
How is newIORef meant to be used so that I only have a single IORef?
The Haskell way is to carry such things implicitly in a State or Reader monad; since the IORef itself doesn't change, and you need the IO monad around anyway to actually use it, you would use a ReaderT IORef IO and then use ask >>= liftIO . readIORef to get the value and similar to write or modify it. (Commonly one uses a type or newtype+newtype deriving to make one's own monad combining them.) -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

Cool. I think I get so i'll have a go.
Thanks again
On Tue, Jan 7, 2014 at 3:21 AM, Brandon Allbery
On Mon, Jan 6, 2014 at 10:15 PM, Courtney Robinson
wrote: On Tue, Jan 7, 2014 at 3:03 AM, Brandon Allbery
wrote: behind
Oh I see, thanks for the info. really helpful. It brings about another question now.
How is newIORef meant to be used so that I only have a single IORef?
The Haskell way is to carry such things implicitly in a State or Reader monad; since the IORef itself doesn't change, and you need the IO monad around anyway to actually use it, you would use a ReaderT IORef IO and then use ask >>= liftIO . readIORef to get the value and similar to write or modify it. (Commonly one uses a type or newtype+newtype deriving to make one's own monad combining them.)
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
-- Courtney Robinson courtney@crlog.info http://crlog.info 07535691628 (No private #s)

On 07/01/14 03:21, Brandon Allbery wrote:
On Mon, Jan 6, 2014 at 10:15 PM, Courtney Robinson
mailto:courtney@crlog.info> wrote: On Tue, Jan 7, 2014 at 3:03 AM, Brandon Allbery
mailto:allbery.b@gmail.com> wrote: behind
Oh I see, thanks for the info. really helpful. It brings about another question now.
How is newIORef meant to be used so that I only have a single IORef?
The Haskell way is to carry such things implicitly in a State or Reader monad; since the IORef itself doesn't change, and you need the IO monad around anyway to actually use it, you would use a ReaderT IORef IO and then use ask >>= liftIO . readIORef to get the value and similar to write or modify it. (Commonly one uses a type or newtype+newtype deriving to make one's own monad combining them.)
You don't have to go that far though, if you want a 'global' IORef then you simply make it at the top of your program and then pass it around to anyone who needs access it to: main :: IO () main = do counter <- newIORef 0 doThingsWithCounter counter doThingsWithCounter :: IORef Int -> IO () doThingsWithCounter counter = |atomicModifyIORef counter $\x -> lety =x +1in(y,y) |So this gives you a way to have global variables, but without the pain that they can bring in other languages. The Reader monad stuff that Brandon suggests is a way to implicitly have this IORef passed around everywhere, which can be useful if you have deeply nested calls where only the children really need access to the IORef - it saves you having to add a new parameter everywhere. - ocharles ||
participants (3)
-
Brandon Allbery
-
Courtney Robinson
-
Oliver Charles