@@ -94,33 +94,62 @@ gen_sr_ab = mkTool $ \ ts (an, sr) -> mkArbitraryInstance ts (nodeRepT an) (bdy
9494 -- to generate a list of lists, each sublist being the shrinking of a single
9595 -- individual field, and finally mconcat everything together.
9696 -- Example:
97- -- shrink = \(Foo a b c) ->
98- -- (Foo <$> shrink a <*> pure b <*> pure c) ++
99- -- (Foo <$> pure a <*> shrink b <*> pure c) ++
100- -- (Foo <$> pure a <*> pure b <*> shrink c)
97+ --
98+ -- shrink = \ x ->
99+ -- case x of
100+ -- Foo a b c ->
101+ -- concat [ Foo <$> shrink a <*> pure b <*> pure c
102+ -- , Foo <$> pure a <*> shrink b <*> pure c
103+ -- , Foo <$> pure a <*> pure b <*> shrink c
104+ -- ]
105+ --
101106 shrinkRecord :: APINode -> SpecRecord -> ExpQ
102107 shrinkRecord an sr = do
103- x <- newName " x"
104- -- Matches the fields of the record with fresh variables
105- -- [( "field1", "field1"), ("field2", "field2") ... ]
106- recordPatterns <-
107- forM (srFields sr) $ \ (fn,_) -> do
108- let freshRecName = pref_field_nm an fn
109- freshPatName <- nodeFieldP an fn
110- pure (freshRecName,freshPatName)
108+ -- List of field names in the record
109+ let fields :: [Name ]
110+ fields = map (pref_field_nm an . fst ) (srFields sr)
111+
112+ -- Given a list of fields with a distinguished element, construct
113+ -- Foo <$> pure x0 <*> ... <*> shrink xM <*> ... <*> pure xN
114+ -- where the boolean indicates which field should use 'shrink'.
115+ let shrinkMarkedField :: [(Bool , Name )] -> ExpQ
116+ shrinkMarkedField flds =
117+ applicativeE (nodeConE an) $
118+ flip map flds $ \ (shrunk, fld) ->
119+ if shrunk then [e | QC.shrink $(varE fld) |]
120+ else [e | pure $(varE fld) |]
121+
122+ -- Construct the list
123+ -- [ Foo <$> shrink a <*> pure b <*> ...
124+ -- , Foo <$> pure a <*> shrink b <*> ...
125+ -- , ...
126+ -- ]
127+ let shrinkAllFields :: ExpQ
128+ shrinkAllFields = listE (map shrinkMarkedField (distinguishedElements fields))
111129
130+ x <- newName " x"
112131 lamE [varP x] $
113132 caseE (varE x) [
114- -- temporary, not correct. it won't shrink properly.
115- match (recP nm (map pure recordPatterns))
116- (normalB $ applicativeE (nodeConE an) $
117- flip map recordPatterns $ \ (fld, _pat) ->
118- [e | QC.shrink $(varE fld) |]
119- ) []
133+ -- Foo a b c -> concat [...]
134+ match (recP nm (map (\ n -> fieldPat n (varP n)) fields))
135+ (normalB [e | concat $shrinkAllFields |])
136+ []
120137 ]
121138 where
122139 nm = rep_type_nm an
123140
141+ -- | Turn an N-element list into N lists of N pairs, each of which has a single
142+ -- distinguished element marked True.
143+ --
144+ -- >>> distinguishedElements "abc"
145+ -- [[(True,'a'),(False,'b'),(False,'c')],[(False,'a'),(True,'b'),(False,'c')],[(False,'a'),(False,'b'),(True,'c')]]
146+ --
147+ distinguishedElements :: [a ] -> [[(Bool , a )]]
148+ distinguishedElements [] = []
149+ distinguishedElements (x: xs) = ((True , x) : map ((,) False ) xs)
150+ : map ((False , x) : ) (distinguishedElements xs)
151+
152+
124153-- | Generate an 'Arbitrary' instance for a union:
125154--
126155-- > instance Arbitrary Foo where
0 commit comments