I recently started a toy Haskell project implementing some concepts
related to Event Sourcing and CQRS. I find strong the abstractions and
type system from Haskell usually help in solidifing my understanding
of most concepts.
This post will start things off only tangentially related to CQRS and will
describe a small DSL I’ve put together for modelling validation of
We’ll end up being able to compose commands from smaller parts, while
still being able to run validations against them in a “transactional” way,
meaning the validation will run before any side-effects occur, and if there
is a failure, all side-effects will be prevented from happening. Essentially,
a unit of work type behavior that arises through correctness of construction.
This will be a win, as composability is always a critical feature of any
well designed software system. It will also lead us to a system that will
be more expressive than something like attributes/annotations in C# or Java,
while keeping our code simple such that it will interact well with our
We will for now skip modelling things like using a read/write model
and use commands that are simple IO actions, such as
addUserCommand :: String -> IO () addUserCommand user = printf "Added user %sn" user setPasswordCommand :: String -> String -> IO () setPasswordCommand user pwd = printf "Set password for user %s to '%s'n" user pwd
I’ll mostly be interested in the side-effects themselves, which are
exemplified as simple print statements.
Now for modelling validations themselves, there are two things I’d
like a validation type to satisfy.
- There should be an “empty” validation, that never fails.
- There should be a way to compose validations into one validation
object, such that it encompasses it’s parts and collects errors from
Naturally, this suggests using a
Monoid. We’ll just use a list in
this example, but I will abstract over monoids, as it will lead to
more flexible code, and will keep me honest about how the API is used.
Now there needs to be a way to combine commands with their validations,
such that we can compose commands while still ensuring that we can run
all validation logic before any side-effects occur.
Of course, Haskell’s standard set of abstractions contains the answer
we need in order to maximize the expressiveness for this API. We want
to combine effectful objects such that the resulting “control flow”
can be predicted ahead of running effects. The interface we need is
Applicative, for applicative functors, a generalization of the
Applicative functors as a generalization of monads, are thus also
somewhat less powerful. This loss of power is however exactly what is
need to achieve our goals.
We define a data type
Attributed that contains an effectful object
m) running side-by-side with a monoid (
data Attributed m w a = Attributed (m a) w
This datatype cannot be made into a monad in a meaningful way, but can
be made into an applicative in the obvious way.
instance (Monoid w, Applicative m) => Applicative (Attributed m w) where pure a = Attributed (pure a) mempty Attributed f v <*> Attributed a w = Attributed (f <*> a) (v <> w)
This code might be hard to understand if you’re not versed in Haskell,
but don’t worry if it looks like opaque, it will not affect the
resulting API, and is really pretty uninteresting. If you want to
understand it, I’d recommend reading up on monoids and applicative
Before we get to the meat of things we need some helper
functions. We’ll define an operator (
#) to apply validations to an
infixr 0 # vs # effect = Attributed effect (mconcat vs)
This will apply a list of validations (monoids) to an effect
(command). Using a list will also have the cute effect of making the
syntax look somewhat like attributes in C#, my paying-the-bills
language of choice.
We also define a simple helper function on lists
assert p err = if p then  else [err]
and use it to write a function for validating the min-length of
minLength name n str = assert (length str >= n) $ printf "%s %s: Min-length is %d" name str n
printf is polymorphic, and above becomes a pure function
to strings, while in the commands it’s side-effecting and prints to
console. (Type system win).
We now can define some commands with validation.
addUserCommand :: String -> Command () addUserCommand user = [ minLength "Username" 5 user ] # printf "Added user %sn" user setPasswordCommand :: String -> String -> Command () setPasswordCommand user pwd = [ minLength "Password" 7 pwd ] # printf "Set password for user %s to '%s'n" user pwd
Above I’ve defined the type
Command as an attributed effect, where
our monoid is a
[String], or list of strings representing error
type Command a = Attributed IO [String] a
Now, let’s say we want to define a new command that both adds a user
and sets the initial password. We can do this with applicative
newUserCommand user pwd = addUserCommand user *> setPasswordCommand user pwd
We use a
run function to execute commands with their validations.
run :: Command a -> IO () run (Attributed command w) = case w of  -> void command errors -> for_ errors $ e -> printf "error: %sn" e
Let’s try it out
*Main> run $ newUserCommand "foo" "password" error: Username foo: Min-length is 5 *Main> run $ newUserCommand "username" "foo" error: Password foo: Min-length is 7 *Main> run $ newUserCommand "username" "password" Added user username Set password for user username to 'password'
Cool. Even if the validation fails for the password, the create user
action is not executed. This could not be the case had we used monadic
composition in something like the similarly constructed writer monad.
To see the flexibility of this abstraction, we’ll do something stupid
like taking a list of usernames and adding all users that start with
the letter ‘s’.
addUsers :: [String] -> Command () addUsers users = for_ users $ userName -> case userName of 's':_ -> addUser userName _ -> pure () -- do nothing
Let’s test it
*Main> run $ addUsers ["simon_marlow", "spj", "pni", "conal", "simon_thompson"] error: Username spj: Min-length is 5 *Main> run $ addUsers ["simon_marlow", "pni", "conal", "simon_thompson"] Added user simon_marlow Added user simon_thompson
Sweet. This example is contrived, but illustrates we can combine
commands using arbitrary “control-flow” such as “for-loops” and
“if-statemens” (or the haskell versions thereof), as long as we don’t have any dependencies on the side-effects themselves, which makes a lot of sense.
The occurence of invalid username “pni” does not fail the computation
as it is never inserted, and even if we use the
for control function
we are still “transactional” over the side effects, so this acheives
what we want.
From here we can extend this abstraction with an explicit read model,
that will be available to validate against, while ensuring no invalid
actions are taking against the write model.
Running without validation
We can of course also execute commands without their validations, simply
by ignoring any attached validation. Since Haskell is lazy by default,
this will come at essentially no runtime cost either.
run_unsafe (Attributed m w) = m
It’s amazing what can be achieved with only a few lines of Haskell, when
we chose abstractions wisely. Check out the full source here.
I find the ability to design programs such as these a big win for
languages like Haskell, and for strong type checking and in particular
the separation of pure and effectful computation via the type system,
as well as design patterns such as monoids and applicatives. These go
a long way of ensuring our programs are correctly constructed, and
lead us towards simple yet expressive code. Perhaps now we can put to rest
ideas such as type systems being the root of all evil.