The problem is simple, but it took me some hours to figure it out. I had a JSON file composed of a single dictionary where the values were lists of numbers, discrete and continuous, and I wanted to keep the different number types while reading it in Haskell.

This was a challenge to me, since my practical Haskell experience had been around implementing some classical data structure algorithms.

# Structuring the solution

From Artyom’s tutorial about Aeson, I had the feeling that my main problem would be to define a type to describe the numerical values inside the arrays. I started from there.

The name BinVal comes from the fact that those numbers represent bin edges for data binning/categorization.

From Aeson, the most important function to me would be the decode:

As discussed in the tutorial and seen from the type information, parseJSON is another important function. At this point I knew that a good start would be making the function decode to work for BinVal:

I needed to make BinVal a member of the type class FromJSON and here was the part that took me a lot of time.

OK, understood something here. I wanted to handle the numeric case of Value and it seemed that I needed to return something of the type Parser BinVal. I spent a lot of time messing around Json.withScientific trying to make parseJSON return a Parser BinVal and I was really lost with the types and the tutorial examples. This gist helped me to understand that handling a specific subtype of Value didn’t need to be complicated, my parseJSON could start like this:

Cool, I didn’t need Json.withScientific. Hoogle also helped to find the function floatingOrInteger of the package scientific. The code was going somewhere:

I felt I was very close, but I still didn’t know how to generate a Parser. I thought about many things, tried to imagine some kind of recursion or some other complicated typed messed stuff. Seeing the mention of mapM in the tutorial made everything even more confusing at the beginning, but it actually pointed me to the right direction.

I had noticed that Parser was some kind of type “container”, but I didn’t realized it was a monadic type (actually, I didn’t read the tutorial slowly enough to pay attention to this). After noticing the mapM part, I knew that I needed to put a BinValF f and a BinValI i inside the monadic type Parser.

I started to carefully read again the tutorial. The amount of times I saw return made me wonder about its type signature:

Voilà! That is the answer! return could take a type and wrap it with a monadic container.

# Complete parser

From the tutorial’s section “Unknown field names”, I defined the complete structure of my JSON file as the simple type alias Bins:

Cool! We are ready to go!

The complete solution looked like this:

Categories:

Updated: