5
5
{-# LANGUAGE DeriveDataTypeable #-}
6
6
{-# LANGUAGE DeriveGeneric #-}
7
7
{-# LANGUAGE DeriveLift #-}
8
+ {-# LANGUAGE PatternSynonyms #-}
8
9
{-# LANGUAGE StandaloneDeriving #-}
9
10
{-# LANGUAGE Safe #-}
11
+ {-# LANGUAGE TemplateHaskellQuotes #-}
12
+ {-# LANGUAGE ViewPatterns #-}
10
13
#endif
11
14
12
15
#include "containers.h"
@@ -74,7 +77,11 @@ module Data.Graph (
74
77
75
78
76
79
-- * Strongly Connected Components
77
- , SCC (.. )
80
+ , SCC (..
81
+ #ifdef __GLASGOW_HASKELL__
82
+ , CyclicSCC
83
+ #endif
84
+ )
78
85
79
86
-- ** Construction
80
87
, stronglyConnComp
@@ -107,6 +114,9 @@ import Data.Tree (Tree(Node), Forest)
107
114
108
115
-- std interfaces
109
116
import Data.Foldable as F
117
+ #if MIN_VERSION_base(4,18,0)
118
+ import qualified Data.Foldable1 as F1
119
+ #endif
110
120
import Control.DeepSeq (NFData (rnf ))
111
121
import Data.Maybe
112
122
import Data.Array
@@ -117,14 +127,16 @@ import Data.Array.Unboxed ( UArray )
117
127
import qualified Data.Array as UA
118
128
#endif
119
129
import qualified Data.List as L
130
+ import Data.List.NonEmpty (NonEmpty (.. ))
131
+ import qualified Data.List.NonEmpty as NE
120
132
import Data.Functor.Classes
121
133
#if !MIN_VERSION_base(4,11,0)
122
134
import Data.Semigroup (Semigroup (.. ))
123
135
#endif
124
136
#ifdef __GLASGOW_HASKELL__
125
137
import GHC.Generics (Generic , Generic1 )
126
138
import Data.Data (Data )
127
- import Language.Haskell.TH.Syntax (Lift )
139
+ import Language.Haskell.TH.Syntax (Lift ( .. ) )
128
140
-- See Note [ Template Haskell Dependencies ]
129
141
import Language.Haskell.TH ()
130
142
#endif
@@ -139,15 +151,26 @@ default ()
139
151
-------------------------------------------------------------------------
140
152
141
153
-- | Strongly connected component.
142
- data SCC vertex = AcyclicSCC vertex -- ^ A single vertex that is not
143
- -- in any cycle.
144
- | CyclicSCC [vertex ] -- ^ A maximal set of mutually
145
- -- reachable vertices.
154
+ data SCC vertex
155
+ = AcyclicSCC vertex
156
+ -- ^ A single vertex that is not in any cycle.
157
+ | NECyclicSCC {- # UNPACK #-} !(NonEmpty vertex )
158
+ -- ^ A maximal set of mutually reachable vertices.
159
+ --
160
+ -- @since 0.7.0
146
161
deriving ( Eq -- ^ @since 0.5.9
147
162
, Show -- ^ @since 0.5.9
148
163
, Read -- ^ @since 0.5.9
149
164
)
150
165
166
+ -- | Partial pattern synonym for backward compatibility with @containers < 0.7@.
167
+ pattern CyclicSCC :: [vertex ] -> SCC vertex
168
+ pattern CyclicSCC xs <- NECyclicSCC (NE. toList -> xs) where
169
+ CyclicSCC [] = error " CyclicSCC: an argument cannot be an empty list"
170
+ CyclicSCC (x : xs) = NECyclicSCC (x :| xs)
171
+
172
+ {-# COMPLETE AcyclicSCC, CyclicSCC #-}
173
+
151
174
#ifdef __GLASGOW_HASKELL__
152
175
-- | @since 0.5.9
153
176
deriving instance Data vertex => Data (SCC vertex )
@@ -158,47 +181,65 @@ deriving instance Generic1 SCC
158
181
-- | @since 0.5.9
159
182
deriving instance Generic (SCC vertex )
160
183
184
+ -- There is no instance Lift (NonEmpty v) before template-haskell-2.15.
185
+ #if MIN_VERSION_template_haskell(2,15,0)
161
186
-- | @since 0.6.6
162
187
deriving instance Lift vertex => Lift (SCC vertex )
188
+ #else
189
+ instance Lift vertex => Lift (SCC vertex ) where
190
+ lift (AcyclicSCC v) = [| AcyclicSCC v | ]
191
+ lift (NECyclicSCC (v :| vs)) = [| NECyclicSCC (v :| vs) | ]
192
+ #endif
193
+
163
194
#endif
164
195
165
196
-- | @since 0.5.9
166
197
instance Eq1 SCC where
167
198
liftEq eq (AcyclicSCC v1) (AcyclicSCC v2) = eq v1 v2
168
- liftEq eq (CyclicSCC vs1) (CyclicSCC vs2) = liftEq eq vs1 vs2
199
+ liftEq eq (NECyclicSCC vs1) (NECyclicSCC vs2) = liftEq eq vs1 vs2
169
200
liftEq _ _ _ = False
170
201
-- | @since 0.5.9
171
202
instance Show1 SCC where
172
203
liftShowsPrec sp _sl d (AcyclicSCC v) = showsUnaryWith sp " AcyclicSCC" d v
173
- liftShowsPrec _sp sl d (CyclicSCC vs) = showsUnaryWith (const sl) " CyclicSCC " d vs
204
+ liftShowsPrec sp sl d (NECyclicSCC vs) = showsUnaryWith (liftShowsPrec sp sl) " NECyclicSCC " d vs
174
205
-- | @since 0.5.9
175
206
instance Read1 SCC where
176
207
liftReadsPrec rp rl = readsData $
177
208
readsUnaryWith rp " AcyclicSCC" AcyclicSCC <>
209
+ readsUnaryWith (liftReadsPrec rp rl) " NECyclicSCC" NECyclicSCC <>
178
210
readsUnaryWith (const rl) " CyclicSCC" CyclicSCC
179
211
180
212
-- | @since 0.5.9
181
213
instance F. Foldable SCC where
182
214
foldr c n (AcyclicSCC v) = c v n
183
- foldr c n (CyclicSCC vs) = foldr c n vs
215
+ foldr c n (NECyclicSCC vs) = foldr c n vs
216
+
217
+ #if MIN_VERSION_base(4,18,0)
218
+ -- | @since 0.7.0
219
+ instance F1. Foldable1 SCC where
220
+ foldMap1 f (AcyclicSCC v) = f v
221
+ foldMap1 f (NECyclicSCC vs) = F1. foldMap1 f vs
222
+ -- TODO define more methods
223
+ #endif
184
224
185
225
-- | @since 0.5.9
186
226
instance Traversable SCC where
187
- -- We treat the non-empty cyclic case specially to cut one
188
- -- fmap application.
189
227
traverse f (AcyclicSCC vertex) = AcyclicSCC <$> f vertex
190
- traverse _f (CyclicSCC [] ) = pure (CyclicSCC [] )
191
- traverse f (CyclicSCC (x : xs)) =
192
- liftA2 (\ x' xs' -> CyclicSCC (x' : xs')) (f x) (traverse f xs)
228
+ -- Avoid traverse from instance Traversable NonEmpty,
229
+ -- it is redundantly lazy.
230
+ traverse f (NECyclicSCC (x :| xs)) =
231
+ liftA2 (\ x' xs' -> NECyclicSCC (x' :| xs')) (f x) (traverse f xs)
193
232
194
233
instance NFData a => NFData (SCC a ) where
195
234
rnf (AcyclicSCC v) = rnf v
196
- rnf (CyclicSCC vs) = rnf vs
235
+ rnf (NECyclicSCC vs) = rnf vs
197
236
198
237
-- | @since 0.5.4
199
238
instance Functor SCC where
200
239
fmap f (AcyclicSCC v) = AcyclicSCC (f v)
201
- fmap f (CyclicSCC vs) = CyclicSCC (fmap f vs)
240
+ -- Avoid fmap from instance Functor NonEmpty,
241
+ -- it is redundantly lazy.
242
+ fmap f (NECyclicSCC (x :| xs)) = NECyclicSCC (f x :| map f xs)
202
243
203
244
-- | The vertices of a list of strongly connected components.
204
245
flattenSCCs :: [SCC a ] -> [a ]
@@ -207,7 +248,7 @@ flattenSCCs = concatMap flattenSCC
207
248
-- | The vertices of a strongly connected component.
208
249
flattenSCC :: SCC vertex -> [vertex ]
209
250
flattenSCC (AcyclicSCC v) = [v]
210
- flattenSCC (CyclicSCC vs) = vs
251
+ flattenSCC (NECyclicSCC vs) = NE. toList vs
211
252
212
253
-- | \(O((V+E) \log V)\). The strongly connected components of a directed graph,
213
254
-- reverse topologically sorted.
@@ -229,7 +270,8 @@ stronglyConnComp edges0
229
270
= map get_node (stronglyConnCompR edges0)
230
271
where
231
272
get_node (AcyclicSCC (n, _, _)) = AcyclicSCC n
232
- get_node (CyclicSCC triples) = CyclicSCC [n | (n,_,_) <- triples]
273
+ get_node (NECyclicSCC ((n0, _, _) :| triples)) =
274
+ NECyclicSCC (n0 :| [n | (n, _, _) <- triples])
233
275
{-# INLINABLE stronglyConnComp #-}
234
276
235
277
-- | \(O((V+E) \log V)\). The strongly connected components of a directed graph,
@@ -258,11 +300,12 @@ stronglyConnCompR edges0
258
300
where
259
301
(graph, vertex_fn,_) = graphFromEdges edges0
260
302
forest = scc graph
261
- decode (Node v [] ) | mentions_itself v = CyclicSCC [vertex_fn v]
303
+
304
+ decode (Node v [] ) | mentions_itself v = NECyclicSCC (vertex_fn v :| [] )
262
305
| otherwise = AcyclicSCC (vertex_fn v)
263
- decode other = CyclicSCC (dec other [] )
264
- where
265
- dec (Node v ts) vs = vertex_fn v : foldr dec vs ts
306
+ decode ( Node v ts) = NECyclicSCC (vertex_fn v :| foldr dec [] ts )
307
+
308
+ dec (Node v ts) vs = vertex_fn v : foldr dec vs ts
266
309
mentions_itself v = v `elem` (graph ! v)
267
310
{-# INLINABLE stronglyConnCompR #-}
268
311
0 commit comments