from Hacker News

State Monad for the Rest of Us

by arialdomartini on 8/6/24, 6:40 AM with 57 comments

  • by arialdomartini on 8/6/24, 6:40 AM

    A series of articles starting from the very scratch and getting to the State Monad. It's thought to be novice-friendly: although using F#, it assumes no knowledge of it. If only it aroused someone's curiosity around F#, that would make my day.

    It shows how algorithms with mutable state can be implemented with pure functions, with immutable variables only.

    The series itself is an excuse to take several detours on other Functional Programming topics: currying, partial application, recursion, Functors, Applicative Functors.

    The source code includes F# and C# examples. In the next weeks it will be followed by code examples showing how to apply a state monad in practice.

  • by darby_nine on 8/9/24, 2:30 PM

    You should probably mention in the introduction what the state monad is to those who don't use F#. At first blush it just seems redundant—what is a monad if not a representation of state?
  • by ashton314 on 8/9/24, 3:49 PM

    Monad patterns cut down on boilerplate even in languages where you might not strictly “need” them. I’ve been working on a project in Elixir and I found the writer monad to be exactly what I needed. I wrote about it here: https://lambdaland.org/posts/2024-05-01_definitely_not_about...

    A week or two ago, I found myself working in the same codebase. I had to do some refactoring and, thanks to the monad I had already established, the refactoring reduced code while expanding functionality. The best refactors happen when the patterns make it easy to do.

  • by Iceland_jack on 8/9/24, 3:14 PM

    Any function matching the type

        St -> (a, St)
    
    can viewed as `State St' parameterized over `a'. There are several behaviors that organize such functions, such as Monad which "overloads the semicolon" to work on stateful computations. Another behavior implements a stateful interface: `MonadState St'.

        get :: St -> (St, St)
        put :: St -> (St -> ((), St))
    
    With type classes in Haskell, behaviour is type-directed so in order to reap the benefits we declare a new type.

        {-# Language DerivingVia #-}
        {-# Language GADTSyntax  #-}
    
        -- get :: My St
        -- put :: St -> My ()
        newtype My a where
          My :: (St -> (a, St)) -> My a
          deriving (Functor, Applicative, Monad, MonadState St, MonadFix)
          via State St
  • by loa_in_ on 8/9/24, 3:58 PM

    Isn't every monad a state monad?