Live data from Hacker News

Concurrency in Haskell: Fast, Simple, Correct

bitbashing.io

11–20 of 129 posts

Re: Concurrency in Haskell: Fast, Simple, Correct

#11
post #7
post #3

In another life I will be a Haskell programmer

Why not python ?

I’m not the OP, but static types, Hindley-Milner type inference, algebraic data types, and pattern matching can be quite ergonomic. I have also come to appreciate functional programming and how it makes reasoning about and testing code easier.

Re: Concurrency in Haskell: Fast, Simple, Correct

#12
post #10

I thought it was a bit odd that the author claims there’s no mutexes in sight, the TVar is effectively a mutex guard unless I’m misunderstanding this? (I’ve written exactly 0 lines of Haskel). Or is the claim that the lack of ceremony and accidental complexity around threading is the real win for concurrency here?

You are correct, Haskell has quite a few mutex-like types. MVar is one of them. However, if memory serves me right, TVar is a building block for the transactional memory subsystem. The guard on TVar with, say, modifyTVar is not really stopping execution at entrance but simply indicating that the block modifies the variable. In my mental model, some magic happens in an STM block that checks if two concurrent STM block…

https://zio.dev/reference/stm/

Re: Concurrency in Haskell: Fast, Simple, Correct

#13
post #8

I thought it was a bit odd that the author claims there’s no mutexes in sight, the TVar is effectively a mutex guard unless I’m misunderstanding this? (I’ve written exactly 0 lines of Haskel). Or is the claim that the lack of ceremony and accidental complexity around threading is the real win for concurrency here?

No, a TVar is not a mutex guard. A TVar is a software transactional memory (STM) variable. STM works just like a database: you batch together a sequence of operations into a transaction and then execute them. During execution of a transaction, all changes made to the contents of the TVar are stored in a transaction log. If some other transaction occurs during the execution then the whole thing is aborted and re-run.…

https://hackage.haskell.org/package/stm-containers

This library is full of STM-oriented data structures. They perform better than a simple `TVar (Map k v)`.

It's kind of a fun trick actually. The stock Map is just a tree. The STM Map is also a tree [1] but with TVars at each node. So this helps a lot with contention - you only contend along a "spine" instead of across the whole tree, which is O(log n).

[1] Technically a HAMT a la unordered-containers - trie, tree, you get the idea :)

Re: Concurrency in Haskell: Fast, Simple, Correct

#15

Rust has a bunch of these while being maintainable.

What about Haskell concurrency isn't maintainable?

The concurrency stuff in the stdlib + the mainstays in the ecosystem are pretty stable and noncontroversial..there's stuff in Haskell that churn but this is not one of them.

Re: Concurrency in Haskell: Fast, Simple, Correct

#16
post #10

I thought it was a bit odd that the author claims there’s no mutexes in sight, the TVar is effectively a mutex guard unless I’m misunderstanding this? (I’ve written exactly 0 lines of Haskel). Or is the claim that the lack of ceremony and accidental complexity around threading is the real win for concurrency here?

You are correct, Haskell has quite a few mutex-like types. MVar is one of them. However, if memory serves me right, TVar is a building block for the transactional memory subsystem. The guard on TVar with, say, modifyTVar is not really stopping execution at entrance but simply indicating that the block modifies the variable. In my mental model, some magic happens in an STM block that checks if two concurrent STM block…

I think Clojure has some kind of STM too?

Haskell's STM is pretty world-class though. That's fair to say :)

Re: Concurrency in Haskell: Fast, Simple, Correct

#18

I thought it was a bit odd that the author claims there’s no mutexes in sight, the TVar is effectively a mutex guard unless I’m misunderstanding this? (I’ve written exactly 0 lines of Haskel). Or is the claim that the lack of ceremony and accidental complexity around threading is the real win for concurrency here?

No a TVar isn't a mutex guard. As a sibling comment points out it gives you transactional semantics similar to most relational databases.

Here's an example in perhaps more familiar pseudocode.

  var x = "y is greater than 0"
  var y = 1
  
  forkAndRun {() =>
    y = y - 1
    if (y 
    y = y + 1
    if (y > 0) {
      x = "y is greater than 0"
    }
  }
In the above example, it's perfectly possible, depending on how the forked code blocks interact with each other, to end up with

  x = "y is less than or equal to 0"
  y = 1
because we have no guarantee of atomicity/transactionality in what runs within the `forkAndRun` blocks.

The equivalent of what that Haskell code is doing is replacing `var` with a new keyword `transactional_var` and introducing another keyword `atomically` such that we can do

  transactional_var x = "y is greater than 0"
  transactional_var y = 1
  
  forkAndRun {
    atomically {() =>
      y = y - 1
      if (y 
      y = y + 1
      if (y > 0) {
        x = "y is greater than 0"
      }
    }
  }
and never end up with a scenario where `x` and `y` disagree with each other, because all their actions are done atomically together and `x` and `y` are specifically marked so that in an atomic block all changes to the variables either happen together or are all rolled back together (and tried again), just like in a database.

`transactional_var` is the equivalent of a `TVar` and `atomically` is just `atommically`.

Re: Concurrency in Haskell: Fast, Simple, Correct

#19
post #10

Earlier quoted context omitted.

You are correct, Haskell has quite a few mutex-like types. MVar is one of them. However, if memory serves me right, TVar is a building block for the transactional memory subsystem. The guard on TVar with, say, modifyTVar is not really stopping execution at entrance but simply indicating that the block modifies the variable. In my mental model, some magic happens in an STM block that checks if two concurrent STM block…

I think Clojure has some kind of STM too? Haskell's STM is pretty world-class though. That's fair to say :)

Clojure's STM never really took off because, for various reasons, it's not as easy to compose as Haskell's (where you can build up a big library of STM blocks and piece them together at the very edges of your program). As such Clojure's STM implementation doesn't actually have a great reputation within the Clojure ecosystem where it isn't usually used in most production codebases (whereas in Haskell STM is often one of the first tools used in any production codebase with concurrency).

Basically it's the difference between focusing only on transactional variables without having a good way of marking what is and isn't part of a larger transaction and having a higher-order abstraction of an `STM` action that clearly delineates what things are transactions and what aren't.

Post reply on HN