以下是chunksOf
和splitPlaces
from的类型签名Data.List.Split
:
chunksOf :: Int -> [e] -> [[e]]
splitPlaces :: Integral a => [a] -> [e] -> [[e]]
为什么有些功能(如chunksOf
)使用Int
而其他(如splitPlaces
)使用更通用的Integral a
?
以下是chunksOf
和splitPlaces
from的类型签名Data.List.Split
:
chunksOf :: Int -> [e] -> [[e]]
splitPlaces :: Integral a => [a] -> [e] -> [[e]]
为什么有些功能(如chunksOf
)使用Int
而其他(如splitPlaces
)使用更通用的Integral a
?
在这个答案中,我尝试查看界面不一致的历史原因。摘要: Brent 似乎在运行中使一些函数更通用,以帮助制定 QuickCheck 属性。
splitPlaces
通用的?看起来 Brent 概括了 的类型,splitPlaces
以便更轻松地为该函数引入 QuickCheck 属性。QuickCheck 属性使用新类型包装器来控制测试用例的生成,并且通过Integral a
约束,splitPlaces
可以查看这个新类型包装器以进行算术运算。也可以看看:
泛化类型splitPlaces
并引入 QuickCheck 属性的补丁。
关于这些新类型包装器的 QuickCheck 文档。
但是,这是关于 的属性之一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
请注意,QuickCheckps
会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
值。所以我猜想允许任意 Integral 类型的原因是 QuickCheck 属性会失败Int
但会成功Integer
.
chunksOf
不是通用的?chunksOf
使用模式匹配删除新类型包装器的属性。也可以看看:
这是关于 的属性之一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)
请注意,此属性匹配由 QuickCheck 自动生成的参数,并将它们传递给chunksOf
没有 newtype 包装器。对于测试所需的参数chunksOf
,这很容易做到,因为数字没有嵌套在其他类型中。与prop_splitPlaces_preserve
上面相比,转换[NonNegative Integer]
为[Integer]
或[Int]
需要比模式匹配更复杂的东西。
Arbitrary Int
和之间的区别在Arbitrary Integer
这里并不重要,因为该属性不涉及任何可以触发算术溢出的操作。