0
votes

I looking for a safe way to generate instance for a data type which has fields without a deriving class, but such fields have Generic instance.

I think it is very popular case for testing with QuickCheck, cause every type should have Arbitrary. Nobody wants to include Arbitrary instance with production, but otherwise deriving Arbitrary in test module issues Orphan warning.

I can define newtype for User in test module, but I cannot do the same for Name type. It is hard coded inside User.

I understand problem with Orphan instances. They can overlap, but here I want GHC to derive a hidden Arbitrary instance for Name during deriving Arbitrary for UserAr recursively. Such Arbitrary instance for Name should inside Arbitrary for UserAr just like I would wrote it by hands. I think technically it must be feasible at least through Template Haskell. So I asking for details.

-- prod
import GHC.Generics
newtype Name = Name String deriving (Show, Generic)
data User = User Name deriving (Show, Generic)
-- test 
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype UserAr = UserAr User deriving (Show, Arbitrary)
1

1 Answers

4
votes

There's no such thing as a hidden instance in Haskell. The only way to have an instance that can't be used outside of your module is to hide the whole type that it's on. To do that, you need to make a newtype wrapper for the type, and only export the one that doesn't have the instance. You can then make use of GeneralizedNewtypeDeriving and/or DerivingVia to get the other instances you want back.