Exercises in Programming Style–Quarantine

NOTE : read the rest of the series, or check out the source code.

If you enjoy read­ing these exer­cises then please buy Crista’s book to sup­port her work.


Fol­low­ing on from the last post, we will look at the Quar­an­tine style today.


Style 24 – Quarantine


  • Core pro­gram func­tions have no side effects of any kind, includ­ing IO.
  • All IO actions must be con­tained in com­pu­ta­tion sequences that are clear­ly sep­a­rat­ed from the pure func­tions.
  • All sequences that have IO must be called from the main pro­gram.


This style is sim­i­lar to The One (aka Mon­ads) style we saw ear­li­er on. The notable dif­fer­ence here is that only the side-effect­ing IO code need to be con­tained, so we can inter­pret this as the IO Mon­ad style.


Tak­ing inspi­ra­tion from the com­pu­ta­tion expres­sion we built for The One style, we can make some mod­i­fi­ca­tions here.

We’ll start by declar­ing a gener­ic IO<‘a> type that will encap­su­late an IO action. Then we can build a com­pu­ta­tion expres­sion around this wrap­per type.

Unfor­tu­nate­ly do is already a reserved key­word in F#, so we’ll have to make do with do’ instead (see what I did there? )


Now we can add a cou­ple of helper types and meth­ods to wrap around IO oper­a­tions — such as read­ing from a file or print­ing to con­sole — in our IO<‘a> type.


We need to read from files in order to extract words from Pride and Prej­u­dice and to remove stop words, so both func­tions use our do’ com­pu­ta­tion expres­sion. Notice that we’re using the afore­men­tioned File.ReadAllText helper method, which returns an IO<string> so our do’ com­pu­ta­tion expres­sion can bind to.


Oth­er pure func­tions can stay as they are.


But, our main pro­gram will need to be con­tained since it needs to per­form IO oper­a­tions via the extract­Words and removeStop­Words func­tions.


Note that no work has actu­al­ly been done yet.

So far, we have mere­ly com­posed togeth­er what actions (IO and oth­er­wise) we will per­form when this pro­gram is run. To com­plete the puz­zle we need one more thing — a mech­a­nism to exe­cute these side-effect­ing pro­grams.

Some­thing like this IO mod­ule per­haps?


which we can use to exe­cute our main­Pro­gram.


and voila!

Now, the IO oper­a­tions (includ­ing print­ing to the con­sole) will be per­formed along with oth­er pure func­tions.


You can find the source code for this exer­cise here