In questa risposta, provo a esaminare i motivi storici dell'interfaccia incoerente. Sommario: Sembra che Brent abbia reso alcune funzioni più generiche al volo per aiutare a formulare le proprietà di QuickCheck.
Perché è splitPlaces
generico?
Sembra che Brent abbia generalizzato il tipo di splitPlaces
per semplificare l'introduzione delle proprietà QuickCheck per tale funzione. Le proprietà QuickCheck utilizzano wrapper newtype per controllare la generazione del caso di test e, con il vincolo Integral a
, splitPlaces
è possibile esaminare questo wrapper newtype per le operazioni aritmetiche. Vedi anche:
Tuttavia, qui è una delle proprietà su splitPlaces
:
prop_splitPlaces_preserve :: [NonNegative Integer] -> [Elt] -> Bool
prop_splitPlaces_preserve ps l = concat (splitPlaces ps' l) == genericTake (sum ps') l
where ps' = map unNN ps
Nota che QuickCheck genera automaticamente la lista ps
che viene convertito da map unNN ps
prima di essere passato a splitPlaces
. La funzione unNN
rimuove il wrapper NonNegative
, quindi splitPlaces
non ha a che fare con il wrapper NonNegative
. Tuttavia, riceve un argomento di tipo [Integer]
anziché [Int]
, quindi deve ancora essere generico nel tipo numerico.
Qual è lo scopo di utilizzare [NonNegative Integer]
anziché [NonNegative Int]
?
Ho il sospetto che la proprietà sia falsa per [Int]
a causa degli overflow aritmetici durante il calcolo della somma. La proprietà potrebbe anche essere falsificabile tramite QuickCheck perché l'istanza alla fine delegherà a arbitrarySizedBoundedIntegral
che può generare valori molto grandi.
immagino che l'utilizzo di [NonNegative Integer]
aggira invece questo problema in due modi:
- Con
Integer
, non possono verificarsi overflow.
- L'istanza
Arbitrary Integer
invia delegati a arbitrarySizedIntegral
che genera solo valori piccoli.
quindi credo che la ragione per consentire tipi interi arbitrari è che la proprietà QuickCheck fallirebbe per Int
ma riesce per Integer
.
Perché chunksOf
non è generico?
Le proprietà per chunksOf
utilizzano la corrispondenza del modello per rimuovere i wrapper newtype. Vedi anche:
Ecco una delle proprietà su chunksOf
:
prop_chunksOf_all_n :: Positive Int -> NonEmptyList Elt -> Bool
prop_chunksOf_all_n (Positive n) (NonEmpty l) = all ((==n) . length) (init $ chunksOf n l)
notare che la struttura soddisfa sugli argomenti che vengono generati automaticamente da QuickCheck e li passa al chunksOf
senza l'involucro newtype. Per gli argomenti necessari per il test chunksOf
, questo è facile da fare, perché i numeri non sono nidificati in altri tipi. Confronta con prop_splitPlaces_preserve
sopra, dove la conversione da [NonNegative Integer]
a [Integer]
o [Int]
richiede qualcosa di più complicato della semplice corrispondenza del modello.
La differenza tra Arbitrary Int
e Arbitrary Integer
non importa qui, poiché la proprietà non comporta operazioni che possono attivare un overflow aritmetico.
Buona domanda! Non vedo alcuna particolare buona ragione dal punto di vista dell'interfaccia - forse solo un'implementazione leggermente più semplice. Potrebbe usare la standardizzazione. Quale delle due migliori dipende dalla prospettiva, i disaccordi abbonderanno. – luqui