You do not need the case of adding HZeroand HZero. This is already being considered in the second case. Think about how you would add peano to the term level by induction on the first argument:
data Nat = Zero | Succ Nat
add :: Nat -> Nat -> Nat
add Zero y = y
add (Succ x) y = Succ (add x y)
Now, if you use functional dependencies, you are writing a logical program. Therefore, instead of making a recursive call on the right side, you add a constraint on the result of the recursive call on the left:
class (HNat x, HNat y, HNat r) => HAdd x y r | x y -> r
instance (HNat y) => HAdd HZero y y
instance (HAdd x y r) => HAdd (HSucc x) y (HSucc r)
HNat. .
, - DataKinds TypeFamilies. , :
data Nat = Zero | Succ Nat
Nat , . :
type family Add (x :: Nat) (y :: Nat) :: Nat
type instance Add Zero y = y
type instance Add (Succ x) y = Succ (Add x y)
. , "" Nat , HNat.