@@ -11,12 +11,19 @@ import Data.Map.Internal (Map (..), link2, link, bin)
11
11
import Data.Map.Internal.Debug (showTree , showTreeWith , balanced )
12
12
13
13
import Control.Applicative (Const (Const , getConst ), pure , (<$>) , (<*>) )
14
- import Data.Functor.Identity (Identity (runIdentity ))
14
+ import Control.Monad.Trans.State.Strict
15
+ import Control.Monad.Trans.Class
16
+ import Control.Monad (liftM4 )
17
+ import Data.Functor.Identity (Identity (Identity , runIdentity ))
15
18
import Data.Monoid
16
19
import Data.Maybe hiding (mapMaybe )
17
20
import qualified Data.Maybe as Maybe (mapMaybe )
18
21
import Data.Ord
19
22
import Data.Function
23
+ import qualified Data.Foldable as Foldable
24
+ #if MIN_VERSION_base(4,10,0)
25
+ import qualified Data.Bifoldable as Bifoldable
26
+ #endif
20
27
import Prelude hiding (lookup , null , map , filter , foldr , foldl , take , drop , splitAt )
21
28
import qualified Prelude
22
29
@@ -212,10 +219,25 @@ main = defaultMain
212
219
, testProperty " fmap" prop_fmap
213
220
, testProperty " mapkeys" prop_mapkeys
214
221
, testProperty " split" prop_splitModel
222
+ , testProperty " fold" prop_fold
223
+ , testProperty " foldMap" prop_foldMap
224
+ , testProperty " foldMapWithKey" prop_foldMapWithKey
215
225
, testProperty " foldr" prop_foldr
226
+ , testProperty " foldrWithKey" prop_foldrWithKey
216
227
, testProperty " foldr'" prop_foldr'
228
+ , testProperty " foldrWithKey'" prop_foldrWithKey'
217
229
, testProperty " foldl" prop_foldl
230
+ , testProperty " foldlWithKey" prop_foldlWithKey
218
231
, testProperty " foldl'" prop_foldl'
232
+ , testProperty " foldlWithKey'" prop_foldlWithKey'
233
+ #if MIN_VERSION_base(4,10,0)
234
+ , testProperty " bifold" prop_bifold
235
+ , testProperty " bifoldMap" prop_bifoldMap
236
+ , testProperty " bifoldr" prop_bifoldr
237
+ , testProperty " bifoldr'" prop_bifoldr'
238
+ , testProperty " bifoldl" prop_bifoldl
239
+ , testProperty " bifoldl'" prop_bifoldl'
240
+ #endif
219
241
, testProperty " keysSet" prop_keysSet
220
242
, testProperty " fromSet" prop_fromSet
221
243
, testProperty " takeWhileAntitone" prop_takeWhileAntitone
@@ -229,29 +251,92 @@ main = defaultMain
229
251
]
230
252
231
253
{- -------------------------------------------------------------------
232
- Arbitrary trees
254
+ Arbitrary, reasonably balanced trees
233
255
--------------------------------------------------------------------}
234
- instance (Enum k ,Arbitrary a ) => Arbitrary (Map k a ) where
235
- arbitrary = sized (arbtree 0 maxkey)
236
- where maxkey = 10 ^ (5 :: Int )
237
-
238
- arbtree :: (Enum k , Arbitrary a ) => Int -> Int -> Int -> Gen (Map k a )
239
- arbtree lo hi n = do t <- gentree lo hi n
240
- if balanced t then return t else arbtree lo hi n
241
- where gentree lo hi n
242
- | n <= 0 = return Tip
243
- | lo >= hi = return Tip
244
- | otherwise = do { x <- arbitrary
245
- ; i <- choose (lo,hi)
246
- ; m <- choose (1 ,70 )
247
- ; let (ml,mr) | m== (1 :: Int )= (1 ,2 )
248
- | m== 2 = (2 ,1 )
249
- | m== 3 = (1 ,1 )
250
- | otherwise = (2 ,2 )
251
- ; l <- gentree lo (i- 1 ) (n `div` ml)
252
- ; r <- gentree (i+ 1 ) hi (n `div` mr)
253
- ; return (bin (toEnum i) x l r)
254
- }
256
+
257
+ -- | The IsInt class lets us constrain a type variable to be Int in an entirely
258
+ -- standard way. The constraint @ IsInt a @ is essentially equivalent to the
259
+ -- GHC-only constraint @ a ~ Int @, but @ IsInt @ requires manual intervention
260
+ -- to use. If ~ is ever standardized, we should certainly use it instead.
261
+ -- Earlier versions used an Enum constraint, but this is confusing because
262
+ -- not all Enum instances will work properly for the Arbitrary instance here.
263
+ class (Show a , Read a , Integral a , Arbitrary a ) => IsInt a where
264
+ fromIntF :: f Int -> f a
265
+
266
+ instance IsInt Int where
267
+ fromIntF = id
268
+
269
+ -- | Convert an Int to any instance of IsInt
270
+ fromInt :: IsInt a => Int -> a
271
+ fromInt = runIdentity . fromIntF . Identity
272
+
273
+ {- We don't actually need this, but we can add it if we ever do
274
+ toIntF :: IsInt a => g a -> g Int
275
+ toIntF = unf . fromIntF . F $ id
276
+
277
+ newtype F g a b = F {unf :: g b -> a}
278
+
279
+ toInt :: IsInt a => a -> Int
280
+ toInt = runIdentity . toIntF . Identity -}
281
+
282
+
283
+ -- How much the minimum key of an arbitrary map should vary
284
+ positionFactor :: Int
285
+ positionFactor = 1
286
+
287
+ -- How much the gap between consecutive keys in an arbitrary
288
+ -- map should vary
289
+ gapRange :: Int
290
+ gapRange = 5
291
+
292
+ instance (IsInt k , Arbitrary v ) => Arbitrary (Map k v ) where
293
+ arbitrary = sized (\ sz0 -> do
294
+ sz <- choose (0 , sz0)
295
+ middle <- choose (- positionFactor * (sz + 1 ), positionFactor * (sz + 1 ))
296
+ let shift = (sz * (gapRange) + 1 ) `quot` 2
297
+ start = middle - shift
298
+ t <- evalStateT (mkArb step sz) start
299
+ if valid t then pure t else error " Test generated invalid tree!" )
300
+ where
301
+ step = do
302
+ i <- get
303
+ diff <- lift $ choose (1 , gapRange)
304
+ let i' = i + diff
305
+ put i'
306
+ pure (fromInt i')
307
+
308
+ class Monad m => MonadGen m where
309
+ liftGen :: Gen a -> m a
310
+ instance MonadGen Gen where
311
+ liftGen = id
312
+ instance MonadGen m => MonadGen (StateT s m ) where
313
+ liftGen = lift . liftGen
314
+
315
+ -- | Given an action that produces successively larger keys and
316
+ -- a size, produce a map of arbitrary shape with exactly that size.
317
+ mkArb :: (MonadGen m , Arbitrary v ) => m k -> Int -> m (Map k v )
318
+ mkArb step n
319
+ | n <= 0 = return Tip
320
+ | n == 1 = do
321
+ k <- step
322
+ v <- liftGen arbitrary
323
+ return (singleton k v)
324
+ | n == 2 = do
325
+ dir <- liftGen arbitrary
326
+ p <- step
327
+ q <- step
328
+ vOuter <- liftGen arbitrary
329
+ vInner <- liftGen arbitrary
330
+ if dir
331
+ then return (Bin 2 q vOuter (singleton p vInner) Tip )
332
+ else return (Bin 2 p vOuter Tip (singleton q vInner))
333
+ | otherwise = do
334
+ -- This assumes a balance factor of delta = 3
335
+ let upper = (3 * (n - 1 )) `quot` 4
336
+ let lower = (n + 2 ) `quot` 4
337
+ ln <- liftGen $ choose (lower, upper)
338
+ let rn = n - ln - 1
339
+ liftM4 (\ lt x v rt -> Bin n x v lt rt) (mkArb step ln) step (liftGen arbitrary) (mkArb step rn)
255
340
256
341
-- A type with a peculiar Eq instance designed to make sure keys
257
342
-- come from where they're supposed to.
@@ -1365,46 +1450,105 @@ prop_splitModel n ys = length ys > 0 ==>
1365
1450
in toAscList l == sort [(k, v) | (k,v) <- xs, k < n] &&
1366
1451
toAscList r == sort [(k, v) | (k,v) <- xs, k > n]
1367
1452
1368
- prop_foldr :: Int -> [(Int , Int )] -> Property
1369
- prop_foldr n ys = length ys > 0 ==>
1370
- let xs = List. nubBy ((==) `on` fst ) ys
1371
- m = fromList xs
1372
- in foldr (+) n m == List. foldr (+) n (List. map snd xs) &&
1373
- foldr (:) [] m == List. map snd (List. sort xs) &&
1374
- foldrWithKey (\ _ a b -> a + b) n m == List. foldr (+) n (List. map snd xs) &&
1375
- foldrWithKey (\ k _ b -> k + b) n m == List. foldr (+) n (List. map fst xs) &&
1376
- foldrWithKey (\ k x xs -> (k,x): xs) [] m == List. sort xs
1453
+ prop_fold :: Map Int A -> Property
1454
+ prop_fold = \ m -> Foldable. fold (f <$> m) === Foldable. fold (f <$> elems m)
1455
+ where
1456
+ f v = [v]
1377
1457
1458
+ prop_foldMap :: Map Int A -> Property
1459
+ prop_foldMap = \ m -> Foldable. foldMap f m === Foldable. foldMap f (elems m)
1460
+ where
1461
+ f v = [v]
1378
1462
1379
- prop_foldr' :: Int -> [(Int , Int )] -> Property
1380
- prop_foldr' n ys = length ys > 0 ==>
1381
- let xs = List. nubBy ((==) `on` fst ) ys
1382
- m = fromList xs
1383
- in foldr' (+) n m == List. foldr (+) n (List. map snd xs) &&
1384
- foldr' (:) [] m == List. map snd (List. sort xs) &&
1385
- foldrWithKey' (\ _ a b -> a + b) n m == List. foldr (+) n (List. map snd xs) &&
1386
- foldrWithKey' (\ k _ b -> k + b) n m == List. foldr (+) n (List. map fst xs) &&
1387
- foldrWithKey' (\ k x xs -> (k,x): xs) [] m == List. sort xs
1388
-
1389
- prop_foldl :: Int -> [(Int , Int )] -> Property
1390
- prop_foldl n ys = length ys > 0 ==>
1391
- let xs = List. nubBy ((==) `on` fst ) ys
1392
- m = fromList xs
1393
- in foldl (+) n m == List. foldr (+) n (List. map snd xs) &&
1394
- foldl (flip (:) ) [] m == reverse (List. map snd (List. sort xs)) &&
1395
- foldlWithKey (\ b _ a -> a + b) n m == List. foldr (+) n (List. map snd xs) &&
1396
- foldlWithKey (\ b k _ -> k + b) n m == List. foldr (+) n (List. map fst xs) &&
1397
- foldlWithKey (\ xs k x -> (k,x): xs) [] m == reverse (List. sort xs)
1398
-
1399
- prop_foldl' :: Int -> [(Int , Int )] -> Property
1400
- prop_foldl' n ys = length ys > 0 ==>
1401
- let xs = List. nubBy ((==) `on` fst ) ys
1402
- m = fromList xs
1403
- in foldl' (+) n m == List. foldr (+) n (List. map snd xs) &&
1404
- foldl' (flip (:) ) [] m == reverse (List. map snd (List. sort xs)) &&
1405
- foldlWithKey' (\ b _ a -> a + b) n m == List. foldr (+) n (List. map snd xs) &&
1406
- foldlWithKey' (\ b k _ -> k + b) n m == List. foldr (+) n (List. map fst xs) &&
1407
- foldlWithKey' (\ xs k x -> (k,x): xs) [] m == reverse (List. sort xs)
1463
+ prop_foldMapWithKey :: Map Int A -> Property
1464
+ prop_foldMapWithKey = \ m -> foldMapWithKey (curry f) m === Foldable. foldMap f (toList m)
1465
+ where
1466
+ f kv = [kv]
1467
+
1468
+ -- elems is implemented in terms of foldr, so we don't want to rely on it
1469
+ -- when we're trying to test foldr.
1470
+ prop_foldr :: Fun (A , B ) B -> B -> [(Int , A )] -> Property
1471
+ prop_foldr c n ys = foldr c' n m === Foldable. foldr c' n (snd <$> xs)
1472
+ where
1473
+ c' = curry (apply c)
1474
+ xs = List. sortBy (comparing fst ) (List. nubBy ((==) `on` fst ) ys)
1475
+ m = fromList xs
1476
+
1477
+
1478
+ -- toList is implemented in terms of foldrWithKey, so we don't want to rely on it
1479
+ -- when we're trying to test foldrWithKey.
1480
+ prop_foldrWithKey :: Fun (Int , A , B ) B -> B -> [(Int , A )] -> Property
1481
+ prop_foldrWithKey c n ys = foldrWithKey c' n m === Foldable. foldr (uncurry c') n xs
1482
+ where
1483
+ c' k v acc = apply c (k, v, acc)
1484
+ xs = List. sortBy (comparing fst ) (List. nubBy ((==) `on` fst ) ys)
1485
+ m = fromList xs
1486
+
1487
+ prop_foldr' :: Fun (A , B ) B -> B -> Map Int A -> Property
1488
+ prop_foldr' c n m = foldr' c' n m === Foldable. foldr' c' n (elems m)
1489
+ where
1490
+ c' = curry (apply c)
1491
+
1492
+ prop_foldrWithKey' :: Fun (Int , A , B ) B -> B -> Map Int A -> Property
1493
+ prop_foldrWithKey' c n m = foldrWithKey' c' n m === Foldable. foldr' (uncurry c') n (toList m)
1494
+ where
1495
+ c' k v acc = apply c (k, v, acc)
1496
+
1497
+ prop_foldl :: Fun (B , A ) B -> B -> Map Int A -> Property
1498
+ prop_foldl c n m = foldl c' n m === Foldable. foldl c' n (elems m)
1499
+ where
1500
+ c' = curry (apply c)
1501
+
1502
+ prop_foldlWithKey :: Fun (B , Int , A ) B -> B -> Map Int A -> Property
1503
+ prop_foldlWithKey c n m = foldlWithKey c' n m === Foldable. foldl (uncurry . c') n (toList m)
1504
+ where
1505
+ c' acc k v = apply c (acc, k, v)
1506
+
1507
+ prop_foldl' :: Fun (B , A ) B -> B -> Map Int A -> Property
1508
+ prop_foldl' c n m = foldl' c' n m === Foldable. foldl' c' n (elems m)
1509
+ where
1510
+ c' = curry (apply c)
1511
+
1512
+ prop_foldlWithKey' :: Fun (B , Int , A ) B -> B -> Map Int A -> Property
1513
+ prop_foldlWithKey' c n m = foldlWithKey' c' n m === Foldable. foldl' (uncurry . c') n (toList m)
1514
+ where
1515
+ c' acc k v = apply c (acc, k, v)
1516
+
1517
+ #if MIN_VERSION_base(4,10,0)
1518
+ prop_bifold :: Map Int Int -> Property
1519
+ prop_bifold m = Bifoldable. bifold (mapKeys (: [] ) ((: [] ) <$> m)) === Foldable. fold ((\ (k,v) -> [k,v]) <$> toList m)
1520
+
1521
+ prop_bifoldMap :: Map Int Int -> Property
1522
+ prop_bifoldMap m = Bifoldable. bifoldMap (: [] ) (: [] ) m === Foldable. foldMap (\ (k,v) -> [k,v]) (toList m)
1523
+
1524
+ prop_bifoldr :: Fun (Int , B ) B -> Fun (A , B ) B -> B -> Map Int A -> Property
1525
+ prop_bifoldr ck cv n m = Bifoldable. bifoldr ck' cv' n m === Foldable. foldr c' n (toList m)
1526
+ where
1527
+ ck' = curry (apply ck)
1528
+ cv' = curry (apply cv)
1529
+ (k,v) `c'` acc = k `ck'` (v `cv'` acc)
1530
+
1531
+ prop_bifoldr' :: Fun (Int , B ) B -> Fun (A , B ) B -> B -> Map Int A -> Property
1532
+ prop_bifoldr' ck cv n m = Bifoldable. bifoldr' ck' cv' n m === Foldable. foldr' c' n (toList m)
1533
+ where
1534
+ ck' = curry (apply ck)
1535
+ cv' = curry (apply cv)
1536
+ (k,v) `c'` acc = k `ck'` (v `cv'` acc)
1537
+
1538
+ prop_bifoldl :: Fun (B , Int ) B -> Fun (B , A ) B -> B -> Map Int A -> Property
1539
+ prop_bifoldl ck cv n m = Bifoldable. bifoldl ck' cv' n m === Foldable. foldl c' n (toList m)
1540
+ where
1541
+ ck' = curry (apply ck)
1542
+ cv' = curry (apply cv)
1543
+ acc `c'` (k,v) = (acc `ck'` k) `cv'` v
1544
+
1545
+ prop_bifoldl' :: Fun (B , Int ) B -> Fun (B , A ) B -> B -> Map Int A -> Property
1546
+ prop_bifoldl' ck cv n m = Bifoldable. bifoldl' ck' cv' n m === Foldable. foldl' c' n (toList m)
1547
+ where
1548
+ ck' = curry (apply ck)
1549
+ cv' = curry (apply cv)
1550
+ acc `c'` (k,v) = (acc `ck'` k) `cv'` v
1551
+ #endif
1408
1552
1409
1553
prop_keysSet :: [(Int , Int )] -> Bool
1410
1554
prop_keysSet xs =
0 commit comments