Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Haskell: Semicolons vs Monads

Semicolons vs Monads

The reason why Haskell sometimes calls monads "programmable semicolons", is because in imperative semicolon enabled languages, the semicolon acts as a sequencing operator that sequences side effects. It enables the passing of an effectful state space from one statement/expression to the next.

In the same way, the bind >>= and then >> operator in Haskell, allows a sequencing of effects as well, but in a more explicit manner. The effects are often typed as well, depending on the specific type of monad that you are using. When the effect is IO, then it's typed as an IO monad.

The do notation is just a DSL for bind and then. You gain back the line by line syntax that imperative semicolon active languages have, but your program is more typesafe, and the sequencing is more explicit and strict on what you are sequencing. Whereas a semicolon is a bit like a free for all. If we were funny, we would say (;) :: Any a -> (a -> Any b) -> Any b. Where the a may not even be used anyway.

Rust takes a nice approach, where the ; is not needed when you want to return an expression. This allows you to use the semicolon as it is in imperative languages, but also neglect it when you're programming in an expression based manner.

In Haskell, the semicolon still exists, but it's an optional syntactic construct that when combiend with the brace {} syntax, they replace significant whitespace. let {a = 1; b = 2;} in a + b. This way you can use significant whitespace when it's appropriate, and when it's not, you don't need it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment