Ho un tipo di dati Haskell comeQuickCheck: Come utilizzare checker esaustività per prevenire costruttori dimenticate di tipo somma
data Mytype
= C1
| C2 Char
| C3 Int String
Se io case
su un Mytype
e dimenticare di gestire uno dei casi, GHC mi dà un avviso (controllo di esaustività).
Ora voglio scrivere un esempio QuickCheck Arbitrary
per generare MyTypes
come:
instance Arbitrary Mytype where
arbitrary = do
n <- choose (1, 3 :: Int)
case n of
1 -> C1
2 -> C2 <$> arbitrary
3 -> C3 <$> arbitrary <*> someCustomGen
Il problema di questo è che posso aggiungere una nuova alternativa a Mytype
e dimenticare di aggiornare l'istanza arbitraria, quindi avere il mio i test non testano quell'alternativa.
Mi piacerebbe trovare un modo di utilizzare il controllo esaustivo di GHC per ricordarmi di casi dimenticati nella mia istanza arbitraria.
Il migliore che è venuta in mente è
arbitrary = do
x <- elements [C1, C2 undefined, C3 undefined undefined]
case x of
C1 -> C1
C2 _ -> C2 <$> arbitrary
C3 _ _ -> C3 <$> arbitrary <*> someCustomGen
Ma in realtà non si sentono eleganti.
Mi sembra intuitivo che non ci sia una soluzione pulita al 100%, ma apprezzerei tutto ciò che riduce la possibilità di dimenticare questi casi, specialmente in un grande progetto in cui codice e test sono separati.
Solo una nota: Si può scrivere 'C2 {}' invece di 'C2 _' e così via, che almeno fa la sintassi un po 'più bello. – nh2
Si noti che la cosa 'indefinita' fallirà se il costruttore è severo. –
C'è qualche ragione per cui non vuoi derivare automaticamente l'istanza Arbitrary con TH? –