During the last couple of days I didn’t have a chance to do much programming in my spare time and started really missing Haskell. Just a quick reminder: the code I’m working on is the roller library which I’m using to get familiar with the language. If you see something that can be done better, please feel free to comment! Let’s see where I finished the last time…
Oh, ok. I refactored one suite of properties and now it’s time for the remaining tests to follow. The suite I fixed last time was “TypesTests”, now it’s time to address all compilation problems in the “ParseTests” caused by introducing smart constructors. Let’s first see what is breaking:
OK, two erros. This is caused by the constructors not being visible anymore (smart constructors are used instead). Let’s see the test code:
Oh no!
Googling…
As it turns out, there is a way to have smart constructors and pattern match on the regular constructors and it is to use smart destructors (or Church encoding, if more familiar with lambda calculus than me).
OK, let’s try to use this in action.
This is my type with all its constructors:
I am not too sure a type definition should look like this, as the linked example looked slightly different, but it was already like this when I took ownership of the library and don’t want to make too many breaking changes at once. In my case, smart destructor would look something like this:
Wow. That’s certainly a long type declaration. Now I just have to expose the function… done, and start testing.
And this returns True when run. OK, it looks very promising - the destructor makes the decision which constructor to pattern match the
against. Now how do I effectively use it with my QuickCheck properties? Let’s see…
I am going to start with the first failing property:
And here’s another challenge: my destructor can decompose an instance of DiceExpression, but not an instance of Maybe DiceExpression. Not a big problem, though. Let’s add another destructor that can do it:
Done! Now let’s use it in my property:
And it’s working!
And there we go! I have smart constructors and pattern matching, which is super useful when it comes to testing the code. Now I just have to apply the same mechanism to all broken properties and I think I will release new version of roller.
As I build the library, I am adding more and more code to the Types module I am not sure this is the right thing to do. At the moment I don’t see any better way to achieve my goals but as this is a learning process, there probably will be a lot of refactoring as I start seeing my mistakes. For now the code is working predictably and the test coverage starts shaping up, so I couldn’t be happier.