Describes an esoteric technique - at least, it is in Haskell; this would indeed be a common pattern in Common Lisp, as the author notes. Probably not a posting of general interest.
It’s especially a shame that the author mentions that there’s more threadsafe ways to do this, and then doesn’t show how trivial atomicModifyIORef is. incAndRead could be implemented atomically as:
atomicModifyIORef' ref (\i -> (i+1,i))
which adds 1 to the current value and puts it back, and returns the old value. there’s not even any chance for a race between the read and increment.
Excellent, thanks! The reason I think pointing out atomicModifyIORef in Haskell is important is that I think that it shows how simple atomic operating can be in a language with laziness; in most other languages atomic actions are reserved for atomic data types, but in Haskell, you can take a Data.Map.Map and turn it into a safe, concurrent, atomic and fast key value map simply by sticking it in an IOref and using atomicModifyIORef.
Describes an esoteric technique - at least, it is in Haskell; this would indeed be a common pattern in Common Lisp, as the author notes. Probably not a posting of general interest.
I dunno it’s all that esoteric. It shows up a lot with resource management. Basically let’s you treat types as objects you send messages to in IO.
It’s especially a shame that the author mentions that there’s more threadsafe ways to do this, and then doesn’t show how trivial atomicModifyIORef is. incAndRead could be implemented atomically as:
which adds 1 to the current value and puts it back, and returns the old value. there’s not even any chance for a race between the read and increment.
List of purposes for this article:
Show people that the idea that Haskell limits you to being “pure” is nonsense
Port over as directly as possible a pattern from Lisp
Provide indications as to why one might want nested IO () because this post is a follow-up to a previous one about unevaluated IO actions and nesting.
I can’t satisfy everybody’s preferences for content in the post, but I think mentioning atomicModifyIORef is a very good idea here.
I edited the post to include the example you mentioned and suggested a follow-up reader exercise. Thanks for the feedback. :)
Excellent, thanks! The reason I think pointing out atomicModifyIORef in Haskell is important is that I think that it shows how simple atomic operating can be in a language with laziness; in most other languages atomic actions are reserved for atomic data types, but in Haskell, you can take a Data.Map.Map and turn it into a safe, concurrent, atomic and fast key value map simply by sticking it in an IOref and using atomicModifyIORef.