下面是chunksOf
和splitPlaces
類型簽名從Data.List.Split
:爲什麼一些Data.List.Split函數使用`Int`和其他`Integral a`?
chunksOf :: Int -> [e] -> [[e]]
splitPlaces :: Integral a => [a] -> [e] -> [[e]]
爲什麼有些函數(如chunksOf
)使用Int
而其他(如splitPlaces
)使用更通用的Integral a
?
下面是chunksOf
和splitPlaces
類型簽名從Data.List.Split
:爲什麼一些Data.List.Split函數使用`Int`和其他`Integral a`?
chunksOf :: Int -> [e] -> [[e]]
splitPlaces :: Integral a => [a] -> [e] -> [[e]]
爲什麼有些函數(如chunksOf
)使用Int
而其他(如splitPlaces
)使用更通用的Integral a
?
在這個答案中,我試圖看看不一致接口的歷史原因。 摘要:似乎布倫特使一些功能更加通用,以幫助制定QuickCheck屬性。
splitPlaces
是通用的?它看起來好像Brent將splitPlaces
的類型概括爲便於爲該函數引入QuickCheck屬性。 QuickCheck屬性使用newtype包裝來控制測試用例的生成,並且通過Integral a
約束,splitPlaces
可以查看這個新類型包裝的算術運算。也參見:
The patch 一般化的splitPlaces
的類型和引入了快速檢查屬性。
The QuickCheck documentation關於這些新型包裝。
然而,這裏是約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
注意,快速檢查自動生成列表ps
其通過map unNN ps
被傳遞到splitPlaces
之前轉換。 unNN
函數刪除了NonNegative
包裝,因此splitPlaces
不必處理NonNegative
包裝本身。但是,它收到類型[Integer]
而不是[Int]
的參數,所以它仍然需要在數字類型中是通用的。
[NonNegative Integer]
而不是[NonNegative Int]
有什麼意義?我懷疑[Int]
的屬性是錯誤的,因爲計算總和時的算術溢出。該屬性甚至可以通過QuickCheck進行驗證,因爲Arbitrary [NonNegative Integer]
實例最終將委託給arbitrarySizedBoundedIntegral
,這可能會生成非常大的值。
我猜,使用[NonNegative Integer]
,而不是通過兩種方式規避這個問題:
Integer
,不會發生溢出。Arbitrary Integer
實例代表arbitrarySizedIntegral
只生成小值。所以我想,允許任意積分類型的原因是QuickCheck屬性將失敗的Int
但成功爲Integer
。
chunksOf
不是通用的?chunksOf
的屬性使用模式匹配來移除newtype包裝。另請參見:
這裏是關於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)
注意,這家酒店就由快速檢查自動生成的參數匹配,並將它們傳遞到chunksOf
沒有NEWTYPE包裝。對於測試chunksOf
所需的參數,這很容易實現,因爲這些數字不是嵌套在其他類型中。與上面的prop_splitPlaces_preserve
相比,將[NonNegative Integer]
轉換爲[Integer]
或[Int]
需要比模式匹配更復雜的事情。
Arbitrary Int
和Arbitrary Integer
之間的差異在這裏並不重要,因爲該屬性不涉及任何可能觸發算術溢出的操作。
好問題!從界面的角度來看,我沒有看到任何特別的好理由 - 可能只是稍微簡單的實現。可以使用標準化。哪一個更好取決於前景,分歧會比比皆是。 – luqui