Since coincidentally Data.Default defines 0 as the default value for Int, you can use data-default-class to derive it generically with DeriveAnyClass:
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
import Data.Default (Default(..))
import GHC.Generics (Generic(..))
data A = A { x, y, z :: Int }
deriving (Default, Generic)
-- (def :: A) == A 0 0 0
You can make this more explicit with DerivingStrategies and enforce it with -Wmissing-deriving-strategies:
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DeriveGeneric #-}
{-# OPTIONS_GHC -Wmissing-deriving-strategies #-}
import Data.Default (Default(..))
import GHC.Generics (Generic(..))
data A = A { x, y, z :: Int }
deriving (Default, Generic)
deriving anyclass (Default)
deriving stock (Generic)
-- (def :: A) == A 0 0 0
However, Data.Default is a class with no laws; it’s better used to indicate the canonical default value of a more complex configuration-like type, because its choices for primitive types are essentially arbitrary.
So if you are able to change the type a bit, you can alternatively use the generic-deriving package, in one of two ways. First, by using Sum Int as the type of the fields and deriving Semigroup and Monoid instances with generics:
{-# LANGUAGE DeriveGeneric #-}
import Generics.Deriving.Monoid
data A = A { x, y, z :: Sum Int }
deriving (Generic)
instance Monoid A where mempty = memptydefault
instance Semigroup A where (<>) = sappenddefault
-- (mempty :: A) == A 0 0 0
-- A 1 2 3 <> A 4 5 6 == A 5 7 9
Or second—and this is my preference—by replacing the data type with a newtype over a tuple of Ints, and using DerivingVia to derive the instance via Sum Int:
{-# LANGUAGE DerivingVia #-}
newtype A = A (Int, Int, Int)
deriving (Monoid, Semigroup) via (Sum Int, Sum Int, Sum Int)
-- (mempty :: A) == A 0 0 0
-- A 1 2 3 <> A 4 5 6 == A 5 7 9
You can recover the field names using lenses (e.g. x is _1) or by writing getters and setters manually.