Skip to content

Commit 00ce4ef

Browse files
Improve debuggability when a plan fails (#13)
1 parent 18b6480 commit 00ce4ef

File tree

11 files changed

+182
-138
lines changed

11 files changed

+182
-138
lines changed

constrained-generators.cabal

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ source-repository head
1515
type: git
1616
location: https://github.com/input-output-hk/constrained-generators
1717

18+
flag devel
19+
description: Enable development mode
20+
default: False
21+
manual: True
22+
1823
library
1924
exposed-modules:
2025
Constrained.API
@@ -46,6 +51,23 @@ library
4651
Constrained.TypeErrors
4752

4853
hs-source-dirs: src
54+
55+
if flag(devel)
56+
exposed-modules:
57+
Constrained.Examples
58+
Constrained.Examples.Basic
59+
Constrained.Examples.BinTree
60+
Constrained.Examples.CheatSheet
61+
Constrained.Examples.Either
62+
Constrained.Examples.Fold
63+
Constrained.Examples.List
64+
Constrained.Examples.ManualExamples
65+
Constrained.Examples.Map
66+
Constrained.Examples.Set
67+
Constrained.Examples.Tree
68+
69+
hs-source-dirs: examples
70+
4971
default-language: Haskell2010
5072
ghc-options:
5173
-Wall

examples/Constrained/Examples/Basic.hs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,27 @@ wtfSpec = constrained' $ \ [var| options |] [var| mpair |] ->
319319
, assert $ unit ==. lit ()
320320
]
321321
)
322+
323+
manyInconsistent :: Specification (Int, Int, Int, Int, Int, Int)
324+
manyInconsistent = constrained' $ \ [var| a |] b c d e [var| f |] ->
325+
[ assert $ a <. 10
326+
, assert $ b >. a
327+
, assert $ c >. b
328+
, assert $ d >. c
329+
, assert $ e >. d
330+
, f `dependsOn` e
331+
, assert $ f >. 10
332+
, assert $ f <. a
333+
]
334+
335+
manyInconsistentTrans :: Specification (Int, Int, Int, Int, Int, Int)
336+
manyInconsistentTrans = constrained' $ \ [var| a |] [var| b |] c d e [var| f |] ->
337+
[ assert $ a <. 10
338+
, assert $ b <. a
339+
, assert $ c >. b
340+
, assert $ d >. c
341+
, assert $ e >. d
342+
, f `dependsOn` e
343+
, assert $ f >. 10
344+
, assert $ f <. b
345+
]

examples/Constrained/Examples/Map.hs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,16 @@ mapSetSmall = constrained $ \x ->
125125
mapIsJust :: Specification (Int, Int)
126126
mapIsJust = constrained' $ \ [var| x |] [var| y |] ->
127127
just_ x ==. lookup_ y (lit $ Map.fromList [(z, z) | z <- [100 .. 102]])
128+
129+
eitherKeys :: Specification ([Int], [Int], Map (Either Int Int) Int)
130+
eitherKeys = constrained' $ \ [var| as |] [var| bs |] [var| m |] ->
131+
[
132+
forAll' m $ \ [var| k |] _v ->
133+
[ caseOn k
134+
(branch $ \ a -> a `elem_` as)
135+
(branch $ \ b -> b `elem_` bs)
136+
, reify as (map Left) $ \ ls ->
137+
reify bs (map Right) $ \ rs ->
138+
k `elem_` ls ++. rs
139+
]
140+
]

src/Constrained/AbstractSyntax.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ fastInequality _ _ = True
134134
class Syntax (t :: [Type] -> Type -> Type) where
135135
isInfix :: t dom rng -> Bool
136136
isInfix _ = False
137+
137138
prettySymbol ::
138139
forall deps dom rng ann.
139140
t dom rng ->
@@ -305,10 +306,9 @@ instance Pretty (PredD deps) where
305306
sep
306307
[ "memberPred"
307308
, pretty term
308-
, "(" <> viaShow (length vs) <> " items)"
309-
, brackets (fillSep (punctuate "," (map viaShow (NE.toList vs))))
309+
, prettyShowList (NE.toList vs)
310310
]
311-
ElemPred False term vs -> align $ sep ["notMemberPred", pretty term, fillSep (punctuate "," (map viaShow (NE.toList vs)))]
311+
ElemPred False term vs -> align $ sep ["notMemberPred", pretty term, prettyShowList (NE.toList vs)]
312312
Exists _ (x :-> p) -> align $ sep ["exists" <+> viaShow x <+> "in", pretty p]
313313
Let t (x :-> p) -> align $ sep ["let" <+> viaShow x <+> "=" /> pretty t <+> "in", pretty p]
314314
And ps -> braces $ vsep' $ map pretty ps
@@ -377,15 +377,15 @@ instance (Show a, Typeable a, Show (TypeSpecD deps a)) => Pretty (WithPrec (Spec
377377
ExplainSpec es z -> "ExplainSpec" <+> viaShow es <+> "$" /> pretty z
378378
ErrorSpec es -> "ErrorSpec" /> vsep' (map fromString (NE.toList es))
379379
TrueSpec -> fromString $ "TrueSpec @(" ++ showType @a ++ ")"
380-
MemberSpec xs -> "MemberSpec" <+> short (NE.toList xs)
380+
MemberSpec xs -> "MemberSpec" <+> prettyShowList (NE.toList xs)
381381
SuspendedSpec x p -> parensIf (d > 10) $ "constrained $ \\" <+> viaShow x <+> "->" /> pretty p
382382
-- TODO: require pretty for `TypeSpec` to make this much nicer
383383
TypeSpecD ts cant ->
384384
parensIf (d > 10) $
385385
"TypeSpec"
386386
/> vsep
387387
[ fromString (showsPrec 11 ts "")
388-
, viaShow cant
388+
, prettyShowList cant
389389
]
390390

391391
instance (Show a, Typeable a, Show (TypeSpecD deps a)) => Pretty (SpecificationD deps a) where

src/Constrained/Base.hs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ import Constrained.FunctionSymbol
9999
import Constrained.GenT
100100
import Constrained.Generic
101101
import Constrained.List hiding (toList)
102-
import Constrained.PrettyUtils
103102
import Constrained.TypeErrors
104103
import Control.Monad.Writer (
105104
Writer,
@@ -671,8 +670,6 @@ instance Show (BaseW d r) where
671670
show FromGenericW = "fromSimpleRep"
672671

673672
instance Syntax BaseW where
674-
prettySymbol ToGenericW (x :> Nil) p = Just $ "to" <+> pretty (WithPrec p x)
675-
prettySymbol FromGenericW (x :> Nil) p = Just $ "from" <+> pretty (WithPrec p x)
676673

677674
instance Semantics BaseW where
678675
semantics FromGenericW = fromSimpleRep

src/Constrained/Env.hs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
{-# LANGUAGE DerivingVia #-}
2+
{-# LANGUAGE ImpredicativeTypes #-}
3+
{-# LANGUAGE ExistentialQuantification #-}
24
{-# LANGUAGE GADTs #-}
35
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
46
{-# LANGUAGE ImportQualifiedPost #-}
@@ -13,6 +15,7 @@ module Constrained.Env (
1315
lookup,
1416
find,
1517
remove,
18+
filterKeys,
1619
) where
1720

1821
import Constrained.Core
@@ -34,7 +37,7 @@ data EnvValue where
3437
deriving instance Show EnvValue
3538

3639
data EnvKey where
37-
EnvKey :: !(Var a) -> EnvKey
40+
EnvKey :: Typeable a => !(Var a) -> EnvKey
3841

3942
instance Eq EnvKey where
4043
EnvKey v == EnvKey v' = nameOf v == nameOf v'
@@ -50,7 +53,7 @@ extend :: (Typeable a, Show a) => Var a -> a -> Env -> Env
5053
extend v a (Env m) = Env $ Map.insert (EnvKey v) (EnvValue a) m
5154

5255
-- | Remove a variable from an environment if it exists
53-
remove :: Var a -> Env -> Env
56+
remove :: Typeable a => Var a -> Env -> Env
5457
remove v (Env m) = Env $ Map.delete (EnvKey v) m
5558

5659
-- | Create a singleton environment
@@ -70,13 +73,18 @@ find env var = do
7073
Just a -> pure a
7174
Nothing -> genError ("Couldn't find " ++ show var ++ " in " ++ show env)
7275

76+
-- | Filter the keys in an env, useful for removing irrelevant variables in
77+
-- error messages
78+
filterKeys :: Env -> (forall a. Typeable a => Var a -> Bool) -> Env
79+
filterKeys (Env m) f = Env $ Map.filterWithKey (\ (EnvKey k) _ -> f k) m
80+
7381
instance Pretty EnvValue where
74-
pretty (EnvValue x) = pretty $ take 80 (show x)
82+
pretty (EnvValue x) = viaShow x
7583

7684
instance Pretty EnvKey where
7785
pretty (EnvKey x) = viaShow x
7886

7987
instance Pretty Env where
80-
pretty (Env m) = vsep ("Env" : (map f (Map.toList m)))
88+
pretty (Env m) = vsep (map f (Map.toList m))
8189
where
8290
f (k, v) = hsep [pretty k, "->", pretty v]

0 commit comments

Comments
 (0)