I mentioned in my last post that I was looking for a bug in my autoindentation code.
Sadly, strong typing had given me a hint of my problem: I was returning a boolean that I had no use for, but I chose to ignore this by adding an operator that "swallowed" this return value. Yet the source of that boolean return value was my bug. It just took me extra bit of time to find it.
My parser monad is like a Maybe monad: when a monadic expression fails, the current expression branch stops and returns the failure up the call stack. If the failure happens to be within a higher order control structure, like an "or" statement or a "star" or "plus" repetition (for pattern matching), then another expression branch may be pursued which may succeed.
On the other hand, a monadic expression may return a value. For example, a number may be parsed, and the number may be returned by the monadic expression.
It just so happened that my test to check if I was starting or not a block (for the autoindentation detection) was conceptually returning a boolean. Yet in fact it was not, it was either succeeding, or not, in its "higher order monadic logic". The correct code is something like: "if cond then return () else fail withErrorTagX" , while the false code reads "return cond" . When the second code fails, it returns a the failure (as a boolean) but it does not cause a change of execution behavior.
My autoindent code had three monadic functions: beginBlock, endBlock, checkNotBeginOrEnd.
The two first functions had the correct logic, the "check..." didn't. This last function was doing what its name was implying: it was checking, with pedantic code in the form of "if beginOfBlock then return false else if endOfBlock then return false else return true". But it should have said "if .. then fail ..."
I had two goals with this post. The first was to make clear the "dual level" of thinking that goes on when working with monadic constructions that have their own execution semantics. My second goal was to remark that execution logic is not the same as good old boolean logic. In my monadic operators, I have boolean operators, like "or", "and", "andNot". I come to realize that this denomination is not good because these are really not boolean operators and should not be confused with them.