Skip to content

Commit afb58d6

Browse files
committed
Add Tim's changes
1 parent 35b625e commit afb58d6

File tree

7 files changed

+111
-54
lines changed

7 files changed

+111
-54
lines changed

src/Constrained/Base.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ module Constrained.Base (
7272
-- * Building `Pred`, `Specification`, `Term` etc.
7373
bind,
7474
name,
75+
named,
7576

7677
-- * TODO: documentme
7778
propagateSpec,
@@ -771,6 +772,12 @@ name :: String -> Term a -> Term a
771772
name nh (V (Var i _)) = V (Var i nh)
772773
name _ _ = error "applying name to non-var thing! Shame on you!"
773774

775+
-- | Give a Term a nameHint, if its a Var, and doesn't already have one,
776+
-- otherwise return the Term unchanged.
777+
named :: String -> Term a -> Term a
778+
named nh t@(V (Var i x)) = if x /= "v" then t else V (Var i nh)
779+
named _ t = t
780+
774781
-- | Create a `Binder` with a fresh variable, used in e.g. `constrained`
775782
bind :: (HasSpec a, IsPred p) => (Term a -> p) -> Binder a
776783
bind bodyf = newv :-> bodyPred

src/Constrained/GenT.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ module Constrained.GenT (
4040

4141
-- * So far undocumented
4242
fatalError,
43+
getMessages,
4344
catMessages,
4445
catMessageList,
4546
explain,

src/Constrained/Generation.hs

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ module Constrained.Generation (
5151
pattern SumSpec,
5252
) where
5353

54+
-- import Debug.Trace
5455
import Constrained.AbstractSyntax
5556
import Constrained.Base
5657
import Constrained.Conformance
@@ -97,39 +98,40 @@ import Prelude hiding (cycle, pred)
9798
-- generators are not flexible enough.
9899
genFromSpecT ::
99100
forall a m. (HasCallStack, HasSpec a, MonadGenError m) => Specification a -> GenT m a
100-
genFromSpecT (simplifySpec -> spec) = case spec of
101-
ExplainSpec [] s -> genFromSpecT s
102-
ExplainSpec es s -> push es (genFromSpecT s)
103-
MemberSpec as -> explain ("genFromSpecT on spec" ++ show spec) $ pureGen (elements (NE.toList as))
104-
TrueSpec -> genFromSpecT (typeSpec $ emptySpec @a)
105-
SuspendedSpec x p
106-
-- NOTE: If `x` isn't free in `p` we still have to try to generate things
107-
-- from `p` to make sure `p` is sat and then we can throw it away. A better
108-
-- approach would be to only do this in the case where we don't know if `p`
109-
-- is sat. The proper way to implement such a sat check is to remove
110-
-- sat-but-unnecessary variables in the optimiser.
111-
| not $ Name x `appearsIn` p -> do
112-
!_ <- genFromPreds mempty p
113-
genFromSpecT TrueSpec
114-
| otherwise -> do
115-
env <- genFromPreds mempty p
116-
Env.find env x
117-
TypeSpec s cant -> do
118-
mode <- getMode
119-
explainNE
120-
( NE.fromList
121-
[ "genFromSpecT on (TypeSpec tspec cant) at type " ++ showType @a
122-
, "tspec = "
123-
, show s
124-
, "cant = " ++ show (short cant)
125-
, "with mode " ++ show mode
126-
]
127-
)
128-
$
129-
-- TODO: we could consider giving `cant` as an argument to `genFromTypeSpec` if this
130-
-- starts giving us trouble.
131-
genFromTypeSpec s `suchThatT` (`notElem` cant)
132-
ErrorSpec e -> genErrorNE e
101+
genFromSpecT (simplifySpec -> spec) =
102+
case spec of
103+
ExplainSpec [] s -> genFromSpecT s
104+
ExplainSpec es s -> push es (genFromSpecT s)
105+
MemberSpec as -> explain ("genFromSpecT on spec" ++ show spec) $ pureGen (elements (NE.toList as))
106+
TrueSpec -> genFromSpecT (typeSpec $ emptySpec @a)
107+
SuspendedSpec x p
108+
-- NOTE: If `x` isn't free in `p` we still have to try to generate things
109+
-- from `p` to make sure `p` is sat and then we can throw it away. A better
110+
-- approach would be to only do this in the case where we don't know if `p`
111+
-- is sat. The proper way to implement such a sat check is to remove
112+
-- sat-but-unnecessary variables in the optimiser.
113+
| not $ Name x `appearsIn` p -> do
114+
!_ <- genFromPreds mempty p
115+
genFromSpecT TrueSpec
116+
| otherwise -> do
117+
env <- genFromPreds mempty p
118+
Env.find env x
119+
TypeSpec s cant -> do
120+
mode <- getMode
121+
explainNE
122+
( NE.fromList
123+
[ "genFromSpecT on (TypeSpec tspec cant) at type " ++ showType @a
124+
, "tspec = "
125+
, show s
126+
, "cant = " ++ show (short cant)
127+
, "with mode " ++ show mode
128+
]
129+
)
130+
$
131+
-- TODO: we could consider giving `cant` as an argument to `genFromTypeSpec` if this
132+
-- starts giving us trouble.
133+
genFromTypeSpec s `suchThatT` (`notElem` cant)
134+
ErrorSpec e -> genErrorNE e
133135

134136
-- | A version of `genFromSpecT` that simply errors if the generator fails
135137
genFromSpec :: forall a. (HasCallStack, HasSpec a) => Specification a -> Gen a
@@ -220,7 +222,10 @@ prepareLinearization p = do
220222
explainNE
221223
( NE.fromList
222224
[ "Linearizing"
223-
, show $ " preds: " <> pretty preds
225+
, show $
226+
" preds: "
227+
<> pretty (take 3 preds)
228+
<> (if length preds > 3 then fromString (" ... " ++ show (length preds - 3) ++ " more.") else "")
224229
, show $ " graph: " <> pretty graph
225230
]
226231
)
@@ -846,7 +851,7 @@ isEmptyPlan (SolverPlan plan _) = null plan
846851

847852
stepPlan :: MonadGenError m => Env -> SolverPlan -> GenT m (Env, SolverPlan)
848853
stepPlan env plan@(SolverPlan [] _) = pure (env, plan)
849-
stepPlan env (SolverPlan (SolverStage x ps spec : pl) gr) = do
854+
stepPlan env (SolverPlan (SolverStage (x :: Var a) ps spec : pl) gr) = do
850855
(spec', specs) <- runGE
851856
$ explain
852857
( show
@@ -864,6 +869,8 @@ stepPlan env (SolverPlan (SolverStage x ps spec : pl) gr) = do
864869
( NE.fromList
865870
( ( "\nStepPlan for variable: "
866871
++ show x
872+
++ "::"
873+
++ showType @a
867874
++ " fails to produce Specification, probably overconstrained."
868875
++ "PS = "
869876
++ unlines (map show ps)
@@ -896,8 +903,10 @@ genFromPreds env0 (optimisePred . optimisePred -> preds) =
896903
go :: Env -> SolverPlan -> GenT m Env
897904
go env plan | isEmptyPlan plan = pure env
898905
go env plan = do
906+
(mess :: String) <- (unlines . map NE.head) <$> getMessages
899907
(env', plan') <-
900-
explain (show $ "Stepping the plan:" /> vsep [pretty plan, pretty env]) $ stepPlan env plan
908+
explain (show (fromString (mess ++ "Stepping the plan:") /> vsep [pretty plan, pretty env])) $
909+
stepPlan env plan
901910
go env' plan'
902911

903912
-- | Push as much information we can backwards through the plan.
@@ -1305,9 +1314,12 @@ data SolverStage where
13051314
} ->
13061315
SolverStage
13071316

1317+
docVar :: Typeable a => Var a -> Doc h
1318+
docVar (v :: Var a) = fromString (show v ++ " :: " ++ showType @a)
1319+
13081320
instance Pretty SolverStage where
13091321
pretty SolverStage {..} =
1310-
viaShow stageVar
1322+
docVar stageVar
13111323
<+> "<-"
13121324
/> vsep'
13131325
( [pretty stageSpec | not $ isTrueSpec stageSpec]

src/Constrained/NumOrd.hs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ module Constrained.NumOrd (
5151
import Constrained.AbstractSyntax
5252
import Constrained.Base
5353
import Constrained.Conformance
54-
import Constrained.Conformance ()
5554
import Constrained.Core (Value (..), unionWithMaybe)
5655
import Constrained.FunctionSymbol
5756
import Constrained.GenT

src/Constrained/PrettyUtils.hs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,22 @@ infixl 5 />
7777
showType :: forall t. Typeable t => String
7878
showType = show (typeRep (Proxy @t))
7979

80+
-- | Set to True if you need to see everything while debugging
81+
verboseShort :: Bool
82+
verboseShort = True
83+
8084
-- | Pretty-print a short list in full and truncate longer lists
8185
short :: forall a x. (Show a, Typeable a) => [a] -> Doc x
8286
short [] = "[]"
8387
short [x] =
8488
let raw = show x
85-
refined = if length raw <= 20 then raw else take 20 raw ++ " ... "
89+
refined = if length raw <= 20 || verboseShort then raw else take 20 raw ++ " ... "
8690
in "[" <+> fromString refined <+> "]"
8791
short xs =
88-
let raw = show xs
89-
in if length raw <= 50
90-
then fromString raw
91-
else "([" <+> viaShow (length xs) <+> "elements ...] @" <> prettyType @a <> ")"
92+
if verboseShort
93+
then fromString $ unlines (map show xs)
94+
else
95+
let raw = show xs
96+
in if length raw <= 50
97+
then fromString raw
98+
else "([" <+> viaShow (length xs) <+> "elements ...] @" <> prettyType @a <> ")"

src/Constrained/Spec/Map.hs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -186,26 +186,40 @@ instance
186186
n <- genFromSpecT size'
187187
let go 0 _ m = pure m
188188
go n' kvs' m = do
189-
mkv <- tryGenT $ genFromSpecT kvs'
189+
-- mkv <- tryGenT $ genFromSpecT kvs'
190+
mkv <- inspect $ genFromSpecT kvs'
190191
case mkv of
191-
Nothing
192-
| sizeOf m `conformsToSpec` size -> pure m
193-
Just (k, v) ->
192+
Result (k, v) ->
194193
go
195194
(n' - 1)
196195
(kvs' <> typeSpec (Cartesian (notEqualSpec k) mempty))
197196
(Map.insert k v m)
198-
_ ->
197+
GenError msgs ->
198+
if sizeOf m `conformsToSpec` size
199+
then pure m
200+
else
201+
genErrorNE
202+
(pure "Gen error while trying to generate enough elements for a Map." <> catMessageList msgs)
203+
FatalError msgs ->
199204
genErrorNE
200205
( NE.fromList
201-
[ "Failed to generate enough elements for the map:"
202-
, " m = " ++ show m
203-
, " n' = " ++ show n'
204-
, show $ " kvs' = " <> pretty kvs'
205-
, show $ " simplifySpec kvs' = " <> pretty (simplifySpec kvs')
206+
[ "Fatal error while trying to generate enough elements for a map:"
207+
, " The ones we have generated so far = " ++ show m
208+
, " The number we need to still generate: n' = " ++ show n'
209+
, "The original size spec " ++ show size
210+
, "The refined size spec " ++ show size'
211+
, "The computed target size " ++ show n
212+
, "Fatal error messages"
213+
, "<<<---"
214+
-- , "The kvs Spec"
215+
-- , " >>>> "++ show $ " kvs' = " <> pretty kvs'
216+
-- , "The simplified kvs Spec"
217+
-- , " >>>> "++ show(pretty (simplifySpec kvs'))
206218
]
219+
<> catMessageList msgs
220+
<> (pure "--->>>")
207221
)
208-
explain (" n = " ++ show n) $ go n kvs mempty
222+
explain (" The number we are trying for: n = " ++ show n) $ go n kvs mempty
209223
genFromTypeSpec (MapSpec mHint mustKeys mustVals size (simplifySpec -> kvs) foldSpec) = do
210224
!mustMap <- explain "Make the mustMap" $ forM (Set.toList mustKeys) $ \k -> do
211225
let vSpec = constrained $ \v -> satisfies (pair_ (Lit k) v) kvs

src/Constrained/Syntax.hs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ module Constrained.Syntax (
3131
explanation,
3232
assertReified,
3333
reify,
34+
reifyWithName,
3435
letBind,
3536
unsafeExists,
3637
forAll,
@@ -210,6 +211,22 @@ reify t f body =
210211
, Explain (pure ("reify " ++ show t ++ " somef $")) $ toPred (body x)
211212
]
212213

214+
reifyWithName ::
215+
( HasSpec a
216+
, HasSpec b
217+
, IsPred p
218+
) =>
219+
String ->
220+
Term a ->
221+
(a -> b) ->
222+
(Term b -> p) ->
223+
Pred
224+
reifyWithName nam t f body =
225+
exists (\eval -> pure $ f (eval t)) $ \x ->
226+
[ reifies (named nam x) t f
227+
, Explain (pure ("reify " ++ show t ++ " somef $")) $ toPred (body (named nam x))
228+
]
229+
213230
-- | Like `suchThat` for constraints
214231
assertReified :: HasSpec a => Term a -> (a -> Bool) -> Pred
215232
-- Note, it is necessary to introduce the extra variable from the `exists` here

0 commit comments

Comments
 (0)