@ocharles While trying to wrap my head around Rel8
, I wrote the following paragraphs to put my ideas in order. Would you say that they are a correct description of how the Query
monad works?
Query
, while being a monad, is a carefully controlled one. Everything bound to the left of <-
won’t be a “plain” value, but one wrapped in an Expr
context. Primitive types are wrapped like Expr Int
. Record types will have each of its components wrapped in Expr
, and it will look like Person Expr
. We can also have tuples like (Expr Int, Person Expr)
.
Inside the Query
monad, you won’t pattern match on sum types directly, in the conventional way, using case
. Instead, you’ll use functions like maybeTable or deconstructADT that “shift” the pattern-match into the Expr
world.
Also, inside Query
type signatures, you shouldn’t use constructors like Maybe
to signify the absence of a value, or Either
to signify alternatives. Instead of them, you need to use MaybeTable
and EitherTable
. A common source of MaybeTable
s is the optional
function.
We can think of select
as a function that removes Expr
wrappers, giving us direct access to values, and also converts MaybeTable
and EitherTable
into Maybe
and Either
, respectively.