How do you break a Monolith into Microservices at Scale? This ebook shows strategies and techniques for building scalable and resilient microservices.

In my Part-1 post on this topic, we actually did all the I/O I'm going to do here. We lazily read in the entire sample data file, a file containing data describing events generated by a process monitor. My next goal was to re-hydrate my Events from the Strings serialized to the file. These Strings were generated by calling the function show on my List of Events.

Time to back up a little. We got show for free, but we had to ask for it. Leaving aside the Event data type for a moment and looking at the simpler Property data type, remember how we defined it:

At that time we discussed "
deriving (Show)" by simply noting it allowed
ghci to know how to output
Property values. Of course, there's more to it than that. The "more" is Haskell typeclasses. A Haskell typeclass defines a set of functions that can be defined to operate on a data type. The
show function is a member of the
Show typeclass and has the following type:

*EventProcessor> :type show
show :: Show a => a -> String

For a moment, let's see what had happened if we had not specified that
Property derives
Show:

If we load this file, then create a
Property, then try to
show it, we see the following:

Prelude> :load simpleProperty.hs
[1 of 1] Compiling Main ( simpleProperty.hs, interpreted )
Ok, modules loaded: Main.
*Main> let prop1 = Property "key1" "value1"
*Main> show prop1
:1:1:
No instance for (Show Property)
arising from a use of `show'
Possible fix: add an instance declaration for (Show Property)
In the expression: show prop1
In an equation for `it': it = show prop1

That's considerably more helpful than a typical compiler error message. The key is the hint to add an instance declaration. In order for the functions of a typeclass to be applicable to your data type, you need to declare an instance of that typeclass that handles your data type. In our case, we can get
Show simply by stating that we derive it. So we go back to our old definition:

That's definitely an improvement. But, back to the subject -- what I want is to be able to read a
String and turn it in to a
Property. First, let's try to read a
String into an
Integer:

*Main> read "5"
:1:1:
Ambiguous type variable `a0' in the constraint:
Read a0) arising from a use of `read'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: read "5"
In an equation for `it': it = read "5"

Again, a helpful hint from
ghci. It basically doesn't know what we are trying to create and suggests adding a type signature. Here's how you would do it:

Haskell now knows we're trying to read an
Integer, so it recognizes that
anInt is an
Integer and knows how to
show it. All of this should tell you that
Integer has defined instances for both
Show and
Read.

Can we get
Read "for free" simply by stating that our data type derives it? It can't hurt to try:

While this appears to be correct, it doesn't do anything that proves I've been able to parse my example-file lines into a
List of
Events. Unfortunately, at this point I'm a little stuck, as I haven't yet figured out how to correctly extract elements from my
Events (I can do so interactively in
ghci, but I am plagued by compiler errors if I try to do so in the
do block).

I'm going to leave this for a while and go back to some online resources/tutorials, then revisit. The problem for me is that I still don't understand the I/O monad, as it's called. It's becoming clear to me that the concept of a monad -- apparently so integral to Haskell -- isn't easily grasped, as evidenced by the overwhelming number of "Here's my take on monads" tutorials on-line (one author, I see, jokes that everyone who learns about monads appears to post a tutorial on the subject shortly thereafter). So I'm off to the Haskell Wiki to learn about monads, then learn some more about Haskell I/O, and then pick up where I left off.