@@ -66,8 +66,6 @@ data MRFailure
66
66
| MalformedDefsFun Term
67
67
| MalformedComp Term
68
68
| NotCompFunType Term
69
- | CoIndHypMismatchWidened FunName FunName CoIndHyp
70
- | CoIndHypMismatchFailure (NormComp , NormComp ) (NormComp , NormComp )
71
69
-- | A local variable binding
72
70
| MRFailureLocalVar LocalName MRFailure
73
71
-- | Information about the context of the failure
@@ -81,8 +79,8 @@ ppWithPrefix :: PrettyInCtx a => String -> a -> PPInCtxM SawDoc
81
79
ppWithPrefix str a = (pretty str <> ) <$> nest 2 <$> (line <> ) <$> prettyInCtx a
82
80
83
81
-- | Pretty-print two objects, prefixed with a 'String' and with a separator
84
- ppWithPrefixSep :: PrettyInCtx a => String -> a -> String -> a - >
85
- PPInCtxM SawDoc
82
+ ppWithPrefixSep :: ( PrettyInCtx a , PrettyInCtx b ) = >
83
+ String -> a -> String -> b -> PPInCtxM SawDoc
86
84
ppWithPrefixSep d1 t2 d3 t4 =
87
85
prettyInCtx t2 >>= \ d2 -> prettyInCtx t4 >>= \ d4 ->
88
86
return $ group (pretty d1 <> nest 2 (line <> d2) <> line <>
@@ -124,13 +122,6 @@ instance PrettyInCtx MRFailure where
124
122
ppWithPrefix " Could not handle computation:" t
125
123
prettyInCtx (NotCompFunType tp) =
126
124
ppWithPrefix " Not a computation or computational function type:" tp
127
- prettyInCtx (CoIndHypMismatchWidened nm1 nm2 _) =
128
- ppWithPrefixSep " [Internal] Trying to widen co-inductive hypothesis on:" nm1 " ," nm2
129
- prettyInCtx (CoIndHypMismatchFailure (tm1, tm2) (tm1', tm2')) =
130
- do pp <- ppWithPrefixSep " " tm1 " |=" tm2
131
- pp' <- ppWithPrefixSep " " tm1' " |=" tm2'
132
- return $ " Could not match co-inductive hypothesis:" <> pp' <> line <>
133
- " with goal:" <> pp
134
125
prettyInCtx (MRFailureLocalVar x err) =
135
126
local (x: ) $ prettyInCtx err
136
127
prettyInCtx (MRFailureCtx ctx err) =
@@ -184,16 +175,34 @@ data CoIndHyp = CoIndHyp {
184
175
-- from outermost to innermost; that is, the uvars as "seen from outside their
185
176
-- scope", which is the reverse of the order of 'mrUVars', below
186
177
coIndHypCtx :: [(LocalName ,Term )],
178
+ -- | The LHS function name
179
+ coIndHypLHSFun :: FunName ,
180
+ -- | The RHS function name
181
+ coIndHypRHSFun :: FunName ,
187
182
-- | The LHS argument expressions @y1, ..., ym@ over the 'coIndHypCtx' uvars
188
183
coIndHypLHS :: [Term ],
189
184
-- | The RHS argument expressions @y1, ..., ym@ over the 'coIndHypCtx' uvars
190
185
coIndHypRHS :: [Term ]
191
186
} deriving Show
192
187
188
+ -- | Extract the @i@th argument on either the left- or right-hand side of a
189
+ -- coinductive hypothesis
190
+ coIndHypArg :: CoIndHyp -> Either Int Int -> Term
191
+ coIndHypArg (CoIndHyp _ _ _ args1 _) (Left i) = args1 !! i
192
+ coIndHypArg (CoIndHyp _ _ _ _ args2) (Right i) = args2 !! i
193
+
193
194
-- | A map from pairs of function names to co-inductive hypotheses over those
194
195
-- names
195
196
type CoIndHyps = Map (FunName , FunName ) CoIndHyp
196
197
198
+ instance PrettyInCtx CoIndHyp where
199
+ prettyInCtx (CoIndHyp ctx f1 f2 args1 args2) =
200
+ local (const $ map fst $ reverse ctx) $
201
+ prettyAppList [return (ppCtx ctx <> " ." ),
202
+ prettyInCtx (FunBind f1 args1 CompFunReturn ),
203
+ return " |=" ,
204
+ prettyInCtx (FunBind f2 args2 CompFunReturn )]
205
+
197
206
-- | An assumption that a named function refines some specificaiton. This has
198
207
-- the form
199
208
--
@@ -244,14 +253,20 @@ data MRState = MRState {
244
253
mrsVars :: MRVarMap
245
254
}
246
255
256
+ -- | The exception type for MR. Solver, which is either a 'MRFailure' or a
257
+ -- widening request
258
+ data MRExn = MRExnFailure MRFailure
259
+ | MRExnWiden FunName FunName [Either Int Int ]
260
+ deriving Show
261
+
247
262
-- | Mr. Monad, the monad used by MR. Solver, which has 'MRInfo' as as a
248
263
-- shared environment, 'MRState' as state, and 'MRFailure' as an exception
249
264
-- type, all over an 'IO' monad
250
265
newtype MRM a = MRM { unMRM :: ReaderT MRInfo (StateT MRState
251
- (ExceptT MRFailure IO )) a }
266
+ (ExceptT MRExn IO )) a }
252
267
deriving (Functor , Applicative , Monad , MonadIO ,
253
268
MonadReader MRInfo , MonadState MRState ,
254
- MonadError MRFailure )
269
+ MonadError MRExn )
255
270
256
271
instance MonadTerm MRM where
257
272
mkTermF = liftSC1 scTermF
@@ -301,23 +316,41 @@ runMRM sc timeout debug assumps m =
301
316
mriUVars = [] , mriCoIndHyps = Map. empty,
302
317
mriAssumptions = true_tm }
303
318
let init_st = MRState { mrsVars = Map. empty }
304
- runExceptT $ flip evalStateT init_st $ flip runReaderT init_info $ unMRM m
319
+ res <- runExceptT $ flip evalStateT init_st $
320
+ flip runReaderT init_info $ unMRM m
321
+ case res of
322
+ Right a -> return $ Right a
323
+ Left (MRExnFailure failure) -> return $ Left failure
324
+ Left exn -> fail (" runMRM: unexpected internal exception: " ++ show exn)
325
+
326
+ -- | Throw an 'MRFailure'
327
+ throwMRFailure :: MRFailure -> MRM a
328
+ throwMRFailure = throwError . MRExnFailure
305
329
306
330
-- | Apply a function to any failure thrown by an 'MRM' computation
307
- mapFailure :: (MRFailure -> MRFailure ) -> MRM a -> MRM a
308
- mapFailure f m = catchError m (throwError . f)
331
+ mapMRFailure :: (MRFailure -> MRFailure ) -> MRM a -> MRM a
332
+ mapMRFailure f m = catchError m $ \ case
333
+ MRExnFailure failure -> throwError $ MRExnFailure $ f failure
334
+ e -> throwError e
335
+
336
+ -- | Catch any 'MRFailure' raised by a computation
337
+ catchFailure :: MRM a -> (MRFailure -> MRM a ) -> MRM a
338
+ catchFailure m f =
339
+ m `catchError` \ case
340
+ MRExnFailure failure -> f failure
341
+ e -> throwError e
309
342
310
343
-- | Try two different 'MRM' computations, combining their failures if needed.
311
344
-- Note that the 'MRState' will reset if the first computation fails.
312
345
mrOr :: MRM a -> MRM a -> MRM a
313
346
mrOr m1 m2 =
314
- catchError m1 $ \ err1 ->
315
- catchError m2 $ \ err2 ->
316
- throwError $ MRFailureDisj err1 err2
347
+ catchFailure m1 $ \ err1 ->
348
+ catchFailure m2 $ \ err2 ->
349
+ throwMRFailure $ MRFailureDisj err1 err2
317
350
318
351
-- | Run an 'MRM' computation in an extended failure context
319
352
withFailureCtx :: FailCtx -> MRM a -> MRM a
320
- withFailureCtx ctx = mapFailure (MRFailureCtx ctx)
353
+ withFailureCtx ctx = mapMRFailure (MRFailureCtx ctx)
321
354
322
355
{-
323
356
-- | Catch any errors thrown by a computation and coerce them to a 'Left'
@@ -394,11 +427,20 @@ mrApplyAll f args = liftSC2 scApplyAll f args >>= liftSC1 betaNormalize
394
427
-- types as SAW core 'Term's, with the least recently bound uvar first, i.e., in
395
428
-- the order as seen "from the outside"
396
429
mrUVarCtx :: MRM [(LocalName ,Term )]
397
- mrUVarCtx = reverse <$> map (\ (nm,Type tp) -> (nm,tp)) <$> mrUVars
430
+ mrUVarCtx = reverse <$> mrUVarCtxRev
431
+
432
+ -- | Get the current context of uvars as a list of variable names and their
433
+ -- types as SAW core 'Term's, with the most recently bound uvar first, i.e., in
434
+ -- the order as seen "from the inside"
435
+ mrUVarCtxRev :: MRM [(LocalName ,Term )]
436
+ mrUVarCtxRev = map (\ (nm,Type tp) -> (nm,tp)) <$> mrUVars
398
437
399
438
-- | Get the type of a 'Term' in the current uvar context
400
439
mrTypeOf :: Term -> MRM Term
401
- mrTypeOf t = mrUVarCtx >>= \ ctx -> liftSC2 scTypeOf' (map snd ctx) t
440
+ mrTypeOf t =
441
+ -- NOTE: scTypeOf' wants the type context in the most recently bound var
442
+ -- first, i.e., in the mrUVarCtxRev order
443
+ mrUVarCtxRev >>= \ ctx -> liftSC2 scTypeOf' (map snd ctx) t
402
444
403
445
-- | Check if two 'Term's are convertible in the 'MRM' monad
404
446
mrConvertible :: Term -> Term -> MRM Bool
@@ -419,7 +461,7 @@ mrFunOutType fname args =
419
461
debugPrint 0 (" Expected: " ++ show (length vars) ++
420
462
" , found: " ++ show (length args))
421
463
debugPretty 0 (" For function: " <> pp_fname <> " with type: " <> pp_ftype)
422
- error " mrFunOutType"
464
+ error " mrFunOutType"
423
465
424
466
-- | Turn a 'LocalName' into one not in a list, adding a suffix if necessary
425
467
uniquifyName :: LocalName -> [LocalName ] -> LocalName
@@ -430,16 +472,19 @@ uniquifyName nm nms =
430
472
Just nm' -> nm'
431
473
Nothing -> error " uniquifyName"
432
474
475
+ -- | Turn a list of 'LocalName's into one names not in a list, adding suffixes
476
+ -- if necessary
477
+ uniquifyNames :: [LocalName ] -> [LocalName ] -> [LocalName ]
478
+ uniquifyNames [] _ = []
479
+ uniquifyNames (nm: nms) nms_other =
480
+ let nm' = uniquifyName nm nms_other in
481
+ nm' : uniquifyNames nms (nm' : nms_other)
482
+
433
483
-- | Run a MR Solver computation in a context extended with a universal
434
484
-- variable, which is passed as a 'Term' to the sub-computation. Note that any
435
485
-- assumptions made in the sub-computation will be lost when it completes.
436
486
withUVar :: LocalName -> Type -> (Term -> MRM a ) -> MRM a
437
- withUVar nm tp m =
438
- do nm' <- uniquifyName nm <$> map fst <$> mrUVars
439
- assumps' <- mrAssumptions >>= liftTerm 0 1
440
- local (\ info -> info { mriUVars = (nm',tp) : mriUVars info,
441
- mriAssumptions = assumps' }) $
442
- mapFailure (MRFailureLocalVar nm') (liftSC1 scLocalVar 0 >>= m)
487
+ withUVar nm (Type tp) m = withUVars [(nm,tp)] (\ [v] -> m v)
443
488
444
489
-- | Run a MR Solver computation in a context extended with a universal variable
445
490
-- and pass it the lifting (in the sense of 'incVars') of an MR Solver term
@@ -453,16 +498,25 @@ withUVarLift nm tp t m =
453
498
-- The variables are bound "outside in", meaning the first variable in the list
454
499
-- is bound outermost, and so will have the highest deBruijn index.
455
500
withUVars :: [(LocalName ,Term )] -> ([Term ] -> MRM a ) -> MRM a
456
- withUVars = helper [] where
457
- -- The extra input list gives the variables that have already been bound, in
458
- -- order from most to least recently bound
459
- helper :: [Term ] -> [(LocalName ,Term )] -> ([Term ] -> MRM a ) -> MRM a
460
- helper vars [] m = m $ reverse vars
461
- helper vars ((nm,tp): ctx) m =
462
- -- FIXME: I think substituting here is wrong, but works on closed terms, so
463
- -- it's fine to use at the top level at least...
464
- substTerm 0 vars tp >>= \ tp' ->
465
- withUVarLift nm (Type tp') vars $ \ var vars' -> helper (var: vars') ctx m
501
+ withUVars [] f = f []
502
+ withUVars ctx f =
503
+ do nms <- uniquifyNames (map fst ctx) <$> map fst <$> mrUVars
504
+ let ctx_u = zip nms $ map (Type . snd ) ctx
505
+ assumps' <- mrAssumptions >>= liftTerm 0 (length ctx)
506
+ vars <- reverse <$> mapM (liftSC1 scLocalVar) [0 .. length ctx - 1 ]
507
+ local (\ info -> info { mriUVars = reverse ctx_u ++ mriUVars info,
508
+ mriAssumptions = assumps' }) $
509
+ foldr (\ nm m -> mapMRFailure (MRFailureLocalVar nm) m) (f vars) nms
510
+
511
+ -- | Run a MR Solver in a top-level context, i.e., with no uvars or assumptions
512
+ withNoUVars :: MRM a -> MRM a
513
+ withNoUVars m =
514
+ do true_tm <- liftSC1 scBool True
515
+ local (\ info -> info { mriUVars = [] , mriAssumptions = true_tm }) m
516
+
517
+ -- | Run a MR Solver in a context of only the specified UVars, no others
518
+ withOnlyUVars :: [(LocalName ,Term )] -> MRM a -> MRM a
519
+ withOnlyUVars vars m = withNoUVars $ withUVars vars $ const m
466
520
467
521
-- | Build 'Term's for all the uvars currently in scope, ordered from least to
468
522
-- most recently bound
@@ -699,32 +753,13 @@ _mrSubstEVarsStrict = mrSubstEVarsStrict
699
753
mrGetCoIndHyp :: FunName -> FunName -> MRM (Maybe CoIndHyp )
700
754
mrGetCoIndHyp nm1 nm2 = Map. lookup (nm1, nm2) <$> mrCoIndHyps
701
755
702
- -- | Run a compuation under the additional co-inductive assumption that
703
- -- @forall x1, ..., xn. F y1 ... ym |= G z1 ... zl@, where @F@ and @G@ are
704
- -- the given 'FunName's, @y1, ..., ym@ and @z1, ..., zl@ are the given
705
- -- argument lists, and @x1, ..., xn@ is the current context of uvars. If
706
- -- while running the given computation a 'CoIndHypMismatchWidened' error is
707
- -- reached with the given names, the state is restored and the computation is
708
- -- re-run with the widened hypothesis. This is done recursively, meaning this
709
- -- function will only return once no 'CoIndHypMismatchWidened' errors are
710
- -- raised with the given names.
711
- withCoIndHyp :: FunName -> [Term ] -> FunName -> [Term ] -> MRM a -> MRM a
712
- withCoIndHyp nm1 args1 nm2 args2 m =
713
- do ctx <- mrUVarCtx
714
- withCoIndHyp' (nm1, nm2) (CoIndHyp ctx args1 args2) m
715
-
716
- -- | The main loop of 'withCoIndHyp'
717
- withCoIndHyp' :: (FunName , FunName ) -> CoIndHyp -> MRM a -> MRM a
718
- withCoIndHyp' (nm1, nm2) hyp@ (CoIndHyp _ args1 args2) m =
719
- do mrDebugPPPrefixSep 1 " withCoIndHyp" (FunBind nm1 args1 CompFunReturn )
720
- " |=" (FunBind nm2 args2 CompFunReturn )
721
- st <- get
722
- hyps' <- Map. insert (nm1, nm2) hyp <$> mrCoIndHyps
723
- (local (\ info -> info { mriCoIndHyps = hyps' }) m) `catchError` \ case
724
- CoIndHypMismatchWidened nm1' nm2' hyp' | nm1 == nm1' && nm2 == nm2'
725
- -> -- FIXME: Could restoring the state here cause any problems?
726
- put st >> withCoIndHyp' (nm1, nm2) hyp' m
727
- e -> throwError e
756
+ -- | Run a compuation under an additional co-inductive assumption
757
+ withCoIndHypRaw :: CoIndHyp -> MRM a -> MRM a
758
+ withCoIndHypRaw hyp m =
759
+ do debugPretty 1 (" withCoIndHyp" <+> ppInEmptyCtx hyp)
760
+ hyps' <- Map. insert (coIndHypLHSFun hyp,
761
+ coIndHypRHSFun hyp) hyp <$> mrCoIndHyps
762
+ local (\ info -> info { mriCoIndHyps = hyps' }) m
728
763
729
764
-- | Generate fresh evars for the context of a 'CoIndHyp' and
730
765
-- substitute them into its arguments and right-hand side
@@ -791,8 +826,8 @@ mrPPInCtx a =
791
826
792
827
-- | Pretty-print the result of 'ppWithPrefixSep' relative to the current uvar
793
828
-- context to 'stderr' if the debug level is at least the 'Int' provided
794
- mrDebugPPPrefixSep :: PrettyInCtx a => Int -> String -> a -> String -> a - >
795
- MRM ()
829
+ mrDebugPPPrefixSep :: ( PrettyInCtx a , PrettyInCtx b ) = >
830
+ Int -> String -> a -> String -> b -> MRM ()
796
831
mrDebugPPPrefixSep i pre a1 sp a2 =
797
832
mrUVars >>= \ ctx ->
798
833
debugPretty i $
0 commit comments