2013-08-25 3 views
5

Hier sind die Art von Signaturen chunksOf und splitPlaces von Data.List.Split:Warum verwenden einige Data.List.Split-Funktionen "Int" und andere "Integral a"?

chunksOf :: Int -> [e] -> [[e]] 
splitPlaces :: Integral a => [a] -> [e] -> [[e]] 

Warum einige Funktionen zu tun (wie chunksOf) verwenden Int während andere (wie splitPlaces) die allgemeinere Integral a verwenden?

+0

Gute Frage! Aus der Sicht der Schnittstelle sehe ich keinen besonderen guten Grund - vielleicht nur eine etwas einfachere Implementierung. Könnte Standardisierung verwenden. Welcher von beiden besser ist, hängt von der Perspektive ab, es wird Unstimmigkeiten geben. – luqui

Antwort

6

In dieser Antwort versuche ich, die historischen Gründe für die inkonsistente Schnittstelle zu betrachten. Zusammenfassung: Es scheint, dass Brent während des Betriebs einige generische Funktionen verwendet hat, um die Formulierung von QuickCheck-Eigenschaften zu erleichtern.

Warum ist splitPlaces generisch?

Es sieht so aus, als würde Brent den Typ splitPlaces verallgemeinern, um die Einführung von QuickCheck-Eigenschaften für diese Funktion zu erleichtern. Die QuickCheck-Eigenschaften verwenden newtype-Wrapper, um die Testfallgenerierung zu steuern, und mit der Integral a-Einschränkung könnte splitPlaces diesen Wrapper des neuen Typs für die arithmetischen Operationen durchsuchen. Siehe auch:

aber hier ist eine der Eigenschaften über 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 

Beachten Sie, dass Quick Check automatisch die Liste ps erzeugt, die durch map unNN ps umgewandelt wird, bevor splitPlaces geleitet wird. Die unNN Funktion entfernt die NonNegative Wrapper, so splitPlaces muss nicht mit der NonNegative Wrapper selbst beschäftigen. Es erhält jedoch ein Argument vom Typ [Integer] anstelle von [Int], sodass es im numerischen Typ immer noch generisch sein muss.

Was ist der Sinn der Verwendung von [NonNegative Integer] anstelle von [NonNegative Int]?

Ich vermute, dass die Eigenschaft für [Int] wegen arithmetischer Überläufe falsch ist, wenn die Summe berechnet wird. Die Eigenschaft könnte sogar durch QuickCheck verfälscht werden, da die Arbitrary [NonNegative Integer] Instanz schließlich an arbitrarySizedBoundedIntegral delegiert wird, die sehr große Werte generieren kann.

Ich denke, dass die Verwendung von [NonNegative Integer] statt dieses Problem auf zwei Arten umgeht:

  1. Mit Integer kann keine Überläufe auftreten.
  2. Die Arbitrary Integer Instanz delegiert an arbitrarySizedIntegral, die nur kleine Werte generiert.

Also ich denke, dass der Grund dafür, dass beliebigen Integral-Typ ist, dass die Quick Check Eigenschaft würde für Int scheitert aber gelingt für Integer.

Warum ist chunksOf nicht generisch?

Die Eigenschaften für chunksOf verwenden Mustervergleich, um die Wrapper des neuen Typs zu entfernen. Siehe auch:

  • The patch, die Eigenschaften für splitEvery einführt.

  • The patch umbenennen splitEvery zu chunksOf.

Dies ist eine der Eigenschaften über 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) 

Beachten Sie, dass diese Eigenschaft auf den Argumenten übereinstimmt, die von Quick Check automatisch generiert werden und übergibt sie an chunksOf ohne newtype-Wrapper. Für die Argumente, die zum Testen chunksOf erforderlich sind, ist dies leicht zu tun, da die Zahlen nicht in anderen Typen verschachtelt sind. Vergleichen Sie mit prop_splitPlaces_preserve oben, wo Konvertierung [NonNegative Integer] zu [Integer] oder [Int] etwas komplizierter als nur Mustervergleich erfordert. Der Unterschied zwischen Arbitrary Int und Arbitrary Integer spielt hier keine Rolle, da die Eigenschaft keine Operationen beinhaltet, die einen arithmetischen Überlauf auslösen können.

Verwandte Themen