News for hackers. Stuff that matters.
Re:State Monad for the Rest of Us by trealira on Friday August 09, 2024 @11:07AM (#41202594)
You can also use it for representing errors, for representing global read-only variables, for representing global write-only variables, for representing non-determinism, for representing continuations, and other things (since you can write your own).

For example, this is a really minimalistic arithmetic syntax tree interpreter in Haskell. You could write errors using the Either type:

  data Term = Constant Int | Divide Term Term
  
  eval :: Term -> Either String Int
  eval (Constant n) = n
  eval (Divide left right) =
    case eval left of
      Left errorString -> Left errorString
      Right leftResult ->
        case eval right of
          Left errorString -> Left errorString
          Right rightResult ->
            if rightResult == 0
              then Left "Division by zero"
              else Right (div leftResult rightResult)
It's cumbersome, and there's a staircase growing. Because Either is a monad, you could rewrite the division op like this:

  eval (Divide left right) = do
    leftResult <- eval left
    rightResult <- eval right
    if rightResult == 0
      then Left "Division by zero"
      else Right (div leftResult rightResult)
This is a good article about the either monad: https://mmhaskell.com/blog/2022/3/3/using-either-as-a-monad

The state monad is basically a wrapper over a pure function that takes a state and returns a tuple with the result and a new state. In an imperative language, you'd just actually change state, rather than doing that.

An example from this wiki page: https://en.wikibooks.org/wiki/Haskell/Understanding_monads/S...

In an imperative language, for pseudo-random numbers, you could modify global variables every time you want a new random number. Haskell lets you do this in IO functions. But a pure way would be to return the result of the new global variable every time.

  -- randomR takes a range, so randomR (1,6) produces a random number between 1 and 6
  rollPair :: StdGen -> ((Int, Int), StdGen)
  rollPair s0 =
    let (r1, s1) = randomR (1,6) s0
        (r2, s2) = randomR (1,6) s1
    in ((r1, r2), s2)
It's annoying. You could use the state monad to simplify this:

  rollDieS :: State StdGen Int
  rollDieS = state (randomR (1,6))

  rollPairS :: State StdGen (Int, Int)
  rollPairS = do
    r1 <- rollDieS
    r2 <- rollDieS
    return (r1, r2)
Re:State Monad for the Rest of Us by darby_nine on Friday August 09, 2024 @11:09AM (#41202616)
> The state monad is basically a wrapper over a pure function that takes a state and returns a tuple with the result and a new state.

So... it's a monad? I don't understand why this is worth calling State as distinct from non-State when that doesn't seem to add any meaning. Surely there must be something implied by a State monad that is not implied by a non-State monad. That seems relevant to call out in an introduction.

Re:State Monad for the Rest of Us by trealira on Friday August 09, 2024 @11:22AM (#41202733)
I don't see why you think all monads are just like the State monad. The Maybe and Either monads have nothing to do with state, for example.
Re:State Monad for the Rest of Us by darby_nine on Friday August 09, 2024 @12:25PM (#41203282)
> The Maybe and Either monads have nothing to do with state, for example.

See this is what I'm talking about. What does `state` mean to you where monads don't have any relation? It's just an abstract structure—what makes something state or not is the context.

Re:State Monad for the Rest of Us by trealira on Friday August 09, 2024 @12:41PM (#41203413)
State can be modeled as a monad, but monads aren't a synonym for state. Just like squares are technically rectangles, but "rectangle" isn't a synonym for "square."

How do I think of the State monad?

- Like a Mealy machine: https://en.wikipedia.org/wiki/Mealy_machine

- Like a pure way to compose functions that use a nameless, global mutable variable.

- As a newtype wrapper over the type "s -> (a, s)" where s is the type of the state and a is the type of the computation.

Re:State Monad for the Rest of Us by trealira on Saturday August 17, 2024 @10:31AM (#41274866)
Just realized I should have written one of these for the Constant evaluation:

  eval (Constant n) = Right n
  eval (Constant n) = return n