How do you guys deal with monads?

For monad heavy code I tend to use a modified elm-format[1] that doesn’t indent code after <| \foo ->.[2]
This allows me to use do m fn = andThen fn m like this:

PrefixOperator operator -> (StateLookup.findModuleOfVar files thisFile Nothing operator) <| \moduleName -> (State.addVarType moduleName operator type_) <| \() -> State.getNextIdAndTick <| \firstArgId -> State.getNextIdAndTick <| \secondArgId -> State.getNextIdAndTick <| \resultId ->
    finish ...

  1. Can’t remember where I coped it from though, sorry to the original author! ↩︎

  2. This means I use the tweaked elm-format in the whole repository or not at all. Anything in between would be madness :slight_smile: ↩︎

Oh cool, that’s at least a good work around for using the elm-do package. Still feels weird using it for Elm though, since most other people in the community won’t understand it.

To add an approach I haven’t seen mentioned yet, I’d tend to write the code like this:

extractTag : String -> Result (List Parser.DeadEnd) ( Tag, String )
extractTag str =
        openTagResult =
   openTagParser str

        insideResult =
                (\open ->
                        ("<" ++ ++ ">" ++ open.afterOpenTag)

        finalResult =
                (\open ( inside, rest ) ->
                    ( { name =
                      , attributes = open.attributes
                      , inside = inside
                    , rest
Example of the same approach with the `(, Cmd msg)` monad
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
        ( newA, aCmd ) =
            updateA msg model.a

        ( newB, bCmd ) =
            updateB msg newA model.b
    ( { model | a = newA, b = newB }
    , Cmd.batch [ aCmd, bCmd ]

The downside is it obviously takes a huge amount of vertical space. Also it doesn’t give a clean pipeline ordering to the flow of information. But I think there are some benefits:

  • it (arguably) makes it easier to focus in detail on what each single step of the code does (and I have some minimal evidence to think that this is less daunting for new developers to understand what’s going on)
  • it allows for even more flexibility in exactly how any errors are combined (though admittedly that’s rarely needed)
  • it lets you have more of a branching structure of data dependencies (as opposed to being required to thread all data through a single pipeline sequence–though again, that kind of flexibility is rarely needed).

Though I agree, I wish there were consensus on a go-to approach for doing this sort of thing in Elm. All the available solutions seem very clunky compared to do-notation.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.