#readwise # This Is Not a Monad Tutorial ![rw-book-cover](https://readwise-assets.s3.amazonaws.com/static/images/article3.5c705a01b476.png) ## Metadata - Author: [[John Azariah]] - Full Title: This Is Not a Monad Tutorial - URL: https://johnazariah.github.io/2022/12/06/this-is-not-a-monad-tutorial.html ## Highlights If we do this for the whole happy path, we get something like this: ```fsharp ErrorChecked<Client, Error> client(RemoteHost host) => config(host.Jumpbox.AuthConfig) .CallWithValue(jbConfig => ssh.Dial("tcp", fmt.Sprintf("%s:%d", host.Jumpbox.URI, host.Jumpbox.Port), jbConfig) .CallWithValue(jbConn => jbConn.Dial("tcp", fmt.Sprintf("%s:%d", host.URI, host.Port)) .CallWithValue(hostConn => config(host.AuthConfig) .CallWithValue(hostConfig => ssh.NewClientConn(hostConn, host.URI, hostConfig) .CallWithValue((ncc, chans, reqs) => ssh.NewClient(ncc, chans, reqs), nil))))); ``` Now, this looks like an abominable mess compared to what we started with. ... However, we’d be hard-pressed to call this a success, because we’ve kind of turned everything inside out, and taken a relatively neat sequence of instructions and converted it into this deeply-indented horror! In fact, **this “deeply-indented horror” has a name: it is actually the program written in a form known as “Continuation Passing Style”, and as we will see later in this blog post, is a universally powerful way to express code.** It turns out that **even a normal sequence of instructions - like the semi-colon separated sequence we’re familiar with - can be *mechanically* converted (de-sugared) into continuation passing style. Of course, we want to go the other way, and apply some form of syntactic sugar to convert this continuation passing style into something more palatable.** This is where the language we’re working with makes a *big* difference. Functional languages like Scala, Haskell and F# have simple and easy ways to put a pleasant syntax on the continuation chain. C# *does* have a way to represent continuation chains around arbitrary wrappers as well. (`go`, on the other hand, unfortunately, does not - and one is cursed to write out the tedious `if err != nil` blocks by hand.) At a naive level, this is what we stated the problem to be: We want to consistently error-check the results of functions called in a sequence of instructions, but we don’t want it to compete for attention from the focus of what this sequence is doing. A slightly more insightful - and perhaps a little more abstract - level, what we really wanted was: **We want a way to sift out a boilerplate pattern from the code and allow us to take the boilerplate as part of the context of executing a sequence of instructions.** ^fve4o6 Now, there are many approaches we could have taken to do this. Let’s summarize the one we took: - **In order to force the caller of a function to treat the returned value in a way that forces the boilerplate to run, we chose to wrap all return values from a function in an opaque unbreakable box.** - Since the returned value is opaque and unbreakable, one way to utilize the contained value is to invert control and package the rest of the instructions into a lambda, which we then pass to the opaque unbreakable box - allowing it to run any boilerplate and then call the lambda with the hidden value. - **The lambda actually has no idea that it’s being executed in this special context.** This is a profound realization, which will lead to some interesting consequences. - **We apply this inversion of control to the rest of the statements, and this results in a deeply nested chain of continuations.** We can also make some observations about this chain - the first of which is that **it’s tail-callable, which means it can run with constant stack space**. This shouldn’t come as any surprise because the initial sequence of instructions was also runnable with constant stack space. - We then apply some syntactic sugar using the mechanics afforded by the language we’re using. ([View Highlight](https://read.readwise.io/read/01gmj5g5594s9tdtha4w6e6qyc)) --- **it’s easy to see that what we’re trying to solve is the problem of composing functions: not plain composition, but composition within a context. ... We had to do some work to get here, but in the end, that’s all we were doing - composing functions in context.** ---