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.
BinVal comes from the fact that those numbers represent bin edges for
From Aeson, the most important function to me would be the
As discussed in the tutorial and seen from the type information,
another important function. At this point I knew that a good start would be
making the function
decode to work for
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
and it seemed that I needed to return something of the type
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
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
Hoogle also helped to find
floatingOrInteger of the package scientific. The code was
I felt I was very close, but I still didn’t know how to generate a
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
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
From the tutorial’s section
“Unknown field names”,
I defined the complete structure of my JSON file as the simple type alias
Cool! We are ready to go!
The complete solution looked like this: