@@ -11,9 +11,13 @@ import Test.QuickCheck.Function (apply)
11
11
import Test.QuickCheck.Poly (A , B , C , OrdA )
12
12
import Control.Monad.Fix (MonadFix (.. ))
13
13
import Control.Monad (ap )
14
- import Data.Foldable (foldl' , toList )
14
+ import Data.Foldable (fold , foldl' , toList )
15
15
import Data.Traversable (foldMapDefault )
16
+ #if !(MIN_VERSION_base(4,11,0))
17
+ import Data.Semigroup (Semigroup ((<>) ))
18
+ #endif
16
19
#if MIN_VERSION_base(4,18,0)
20
+ import Data.List.NonEmpty (NonEmpty (.. ))
17
21
import qualified Data.List.NonEmpty as NE
18
22
import qualified Data.Foldable1 as Foldable1
19
23
#endif
@@ -32,6 +36,7 @@ main = defaultMain $ testGroup "tree-properties"
32
36
, testProperty " monadFix_ls" prop_monadFix_ls
33
37
, testProperty " toList" prop_toList
34
38
, testProperty " foldMap" prop_foldMap
39
+ , testProperty " foldMap_structure" prop_foldMap_structure
35
40
, testProperty " foldl'" prop_foldl'
36
41
, testProperty " foldr1" prop_foldr1
37
42
, testProperty " foldl1" prop_foldl1
@@ -41,8 +46,10 @@ main = defaultMain $ testGroup "tree-properties"
41
46
, testProperty " sum" prop_sum
42
47
, testProperty " product" prop_product
43
48
#if MIN_VERSION_base(4,18,0)
49
+ , testProperty " foldMap1_structure" prop_foldMap1_structure
44
50
, testProperty " toNonEmpty" prop_toNonEmpty
45
51
, testProperty " last" prop_last
52
+ , testProperty " last_path" prop_last_path
46
53
, testProperty " foldrMap1" prop_foldrMap1
47
54
, testProperty " foldlMap1'" prop_foldlMap1'
48
55
, testProperty " foldlMap1" prop_foldlMap1
@@ -86,6 +93,25 @@ data Magma a
86
93
| Magma a :* Magma a
87
94
deriving (Eq , Show )
88
95
96
+ -- Unlawful on purpose.
97
+ instance Semigroup (Magma a ) where
98
+ (<>) = (:*)
99
+
100
+ data UnitalMagma a
101
+ = Unit
102
+ | UInj a
103
+ | UnitalMagma a :** UnitalMagma a
104
+ deriving (Eq , Show )
105
+
106
+ -- Unlawful on purpose.
107
+ instance Semigroup (UnitalMagma a ) where
108
+ (<>) = (:**)
109
+
110
+ -- Unlawful on purpose.
111
+ instance Monoid (UnitalMagma a ) where
112
+ mempty = Unit
113
+ mappend = (<>)
114
+
89
115
----------------------------------------------------------------
90
116
-- Unit tests
91
117
----------------------------------------------------------------
@@ -150,6 +176,14 @@ prop_foldMap t =
150
176
foldMap (: [] ) t === toList t .&&.
151
177
foldMap (: [] ) t === foldMapDefault (: [] ) t
152
178
179
+ -- We use UnitalMagma with foldMap to test that the structure of the fold
180
+ -- follows that of the tree. This is desirable here because we can be more
181
+ -- efficient/lazy with some monoids, such as Data.Monoid.Last, compared
182
+ -- to a foldr-based foldMap.
183
+ prop_foldMap_structure :: Tree A -> Property
184
+ prop_foldMap_structure t =
185
+ foldMap UInj t === foldTree (\ x ys -> fold (UInj x : ys)) t
186
+
153
187
prop_foldl' :: Tree A -> Property
154
188
prop_foldl' t = foldl' (flip (:) ) [] t === reverse (toList t)
155
189
@@ -179,12 +213,32 @@ prop_product :: Tree OrdA -> Property
179
213
prop_product t = product t === product (toList t)
180
214
181
215
#if MIN_VERSION_base(4,18,0)
216
+ -- We use Magma with foldMap1 to test that the structure of the fold follows
217
+ -- that of the tree. This is desirable here because we can be more
218
+ -- efficient/lazy with some semigroups, such as Data.Semigroup.Last, compared
219
+ -- to a foldrMap1-based foldMap1.
220
+ prop_foldMap1_structure :: Tree A -> Property
221
+ prop_foldMap1_structure t =
222
+ Foldable1. foldMap1 Inj t === foldTree (\ x ys -> Foldable1. fold1 (Inj x :| ys)) t
223
+
182
224
prop_toNonEmpty :: Tree A -> Property
183
225
prop_toNonEmpty t = Foldable1. toNonEmpty t === NE. fromList (toList t)
184
226
185
227
prop_last :: Tree A -> Property
186
228
prop_last t = Foldable1. last t === NE. last (Foldable1. toNonEmpty t)
187
229
230
+ -- Tests that last only looks at the path going down to the last leaf.
231
+ prop_last_path :: Tree A -> Property
232
+ prop_last_path t = Foldable1. last (replace t) === Foldable1. last t
233
+ where
234
+ -- Replace all trees with bottom except for the last one.
235
+ replace :: Tree a -> Tree a
236
+ replace (Node x ts) = Node x (replaces ts)
237
+ replaces :: [Tree a ] -> [Tree a ]
238
+ replaces [] = []
239
+ replaces [t] = [replace t]
240
+ replaces (t: ts) = error " error tree" : replaces ts
241
+
188
242
prop_foldrMap1 :: Tree A -> Property
189
243
prop_foldrMap1 t =
190
244
Foldable1. foldrMap1 Inj f t === Foldable1. foldrMap1 Inj f (Foldable1. toNonEmpty t)
0 commit comments