In an imperative setup, this problem simply does not exist.
In an FP setup you need to do brain contortions to get a solution to a trivial problem going.
FP’s power lies providing tools that allow you to decouple processes like “loop forever” or “transform each item of a list” from your application’s own business logic.
Business logic is already separated into other parts of the code, and now I have one concept I need to implement: "loop until exit". I would expect a mature programming language to assist me in mapping this to code as directly as possible, but this is not the case here.
The single concept has to be implemented by combining multiple new concepts: monad combination, lifting, mzero as a terminator... which would be fine if any of these concepts assisted in separating logic, but they do not. They only serve to build the concept of "loop until exit".
Here's an easy one with `whileM` (the one parameter version that is effectively a do-while loop, where the while condition is the expression's return value, there is a two parameter version that takes an independent boolean parameter).
main :: IO ()
main = do
wsUrl <- fetchConnectionUrl
conn <- connectWebSocket wsUrl
whileM $ do
message <- readMessage conn
case message of
MessageA val -> putStrLn "Message A" $> True
MessageB val -> putStrLn "Message B" $> True
Disconnect -> pure False
EDIT: ah I read a little too quickly. The author wants to have arbitrary breaks in the while loop. In that case you can use https://hackage.haskell.org/package/loop-while-1.0.0/docs/Co... which is morally the same thing without the `mzero` jargon (which really is just a generalized `break` here). The other alternative is to just stick with whileM and just normal structured programming if-else blocks that eventually end up returning true or false.