Kata: Panini
Few days ago, with the Software Crafters Lyon, we have tackled the Nearest color.
The main idea is to represent few elements of a panini, a set of ingredient (tomatoes, onion, meat) between two pieces of bread.
This kata aims to practice monoid-based design, finding a neutral element, a composition function and keep invariants.
Let's start by what it is not, a panini is not a monoid, when we add two panini either we have a set (or a list of panini), or we we take the ingredients from one, throw the bread, and put them in another one.
From the description, we can define nutrition facts, as follows:
newtype Fat
= Fat Natural
deriving newtype (Eq, Ord, Num, Show)
deriving (Semigroup, Monoid) via (Sum Fat)
newtype Salt
= Salt Natural
deriving newtype (Eq, Ord, Num, Show)
deriving (Semigroup, Monoid) via (Sum Salt)
newtype Calories
= Calories Natural
deriving newtype (Eq, Ord, Num, Show)
deriving (Semigroup, Monoid) via (Sum Calories)
Note: deriving via is a way to reuse instances from other type, here Sum which use Num to define mempty = 0 and (<>) = (+)
Next elements are union types and are defined as follows:
data Diet
= Vegan
| Vegetarian
| Pescetarian
deriving stock (Eq, Ord, Show, Enum, Bounded, Generic)
deriving (Semigroup, Monoid) via (Min Diet)
data Organic
= Organic
| NonOrganic
deriving stock (Eq, Ord, Show, Enum, Bounded, Generic)
deriving (Semigroup, Monoid) via (Min Organic)
Here we use Min which relies on Ord and Bounded instead.
Finally, we can pack everything together in a Stats type, as follows:
data Stats = Stats
{ diet :: Diet,
organic :: Organic,
fat :: Fat,
salt :: Salt,
calories :: Calories
}
deriving stock (Eq, Show, Generic)
deriving (Semigroup, Monoid) via (Generically Stats)
Generically going field by field to define the instance.
It can latter be use by mconcat.
In summary, this code kata is not a good fit for practising TDD in Haskell, as it is pure domain modeling.