UP | HOME

High Level programming

The Scott Wlaschin’s book. The “Making An Invalid State Unrepresentable” meme.

“Error” handling

  • crash! crash! crash! (Joe Armstrong)
  • option types, “unwrap” (Rust)
  • “smart constructors” (Haskell, F#)
  • proper Monads (with for comprehensions)

In a prototyping, bottom-up code (as in “On Lisp”) always just crash. In Erlang crashes can be automatically restarted in a systematic way.

An Option or a Result could be refactored after the “happy path” has been defined.

Monadic “for-comprehensions” are especially good with Options or Eithers (Results). But just crash at first.

Errors are not always “failures”. They are anticipated possible outcomes and therefore just “forks” of different “paths” (distinct sequences of actions).

Some “errors” are expected conditions and thus would require a separate “branch” or a “path”. Just like an ordinary if expression.

The pattern-matching or case-analysis expressions with multiple “branches”, “arms” or clauses capture this universal pattern.

These expected “splits” or “forks” should be explicitly defined as separate “paths of execution” and made visible to a type-checker.

The universal notion of an empty /slot, an empty /list (or any other empty container) inevitably result in a distinct “alternative path” (sequence of actions).

Monads are just even more abstract, “higher-level” generalization of an abstraction barrier or of a partition or a context (it is a type-class, after all).

A Kleisli Arrow crosses an abstraction barrier, literally. This is the secret mantra.

Some conditions may cause an explicit “lifting” into a different context. There may or may not be the way to “escape” from it.

In a pure functional language there is no “arrow” back “down” (after lifting). There is no “unwrap” in Haskell (because of a Monad instance).

We can pattern-match and bind the wrapped value, but we cannot “see it” from outside of a Monad.

So, what we call an “error” is just an expected condition which requires a “restart”, “backtracking”, and/or “taking a different path”.

It is redundant to partition these “paths” (sequences of actions) with an explicit abstraction barrier, but it helps to maintain the referential transparency property for “applicative actions” and implicitly defines the order of evaluation in a lazy language, so they indeed form a sequence (being properly serialized).

And this is basically it.

Author: <schiptsov@gmail.com>

Email: lngnmn2@yahoo.com

Created: 2023-08-08 Tue 18:39

Emacs 29.1.50 (Org mode 9.7-pre)