-
Notifications
You must be signed in to change notification settings - Fork 46
Description
I was experimenting a bit with the assert function that I added in #388 for enforcing dynamic contracts. In particular, I wanted to implement the following function:
postcondition : (@0 P : b → Set) {{post : ∀ {y} → Dec (P y)}}
→ (f : a → b)
→ (x : a) → ∃ b PNow the way I expected to have to implement it is as follows:
postcondition post f x = assert (post (f x)) (f x ⟨ it ⟩)(where it : {{a}} → a is defined as usual by it {{x}} = x). This leads to the expected Haskell code:
postcondition :: (b -> Bool) -> (a -> b) -> a -> b
postcondition post f x = assert (post (f x)) (f x)However I realized I could also put the assert in the erased portion of the result:
postcondition post f x = f x ⟨ assert (post (f x)) it ⟩which leads to Haskell code without any run-time check:
postcondition post f x = f xNow we could in principle "fix" this by only allowing the assert function to appear in non-erased parts of a program. However this is rather strange because usually things work the other way around.
More generally, the current type of assert is logically inconsistent because you can always simply assert ⊥ to get a proof of anything. This is "fine" in unerased positions since it will lead to a run-time error, but in erased positions this is problematic. Maybe instead of using postulate in the definition of assert it should work more like the definition of error which requires a tactic argument of type ⊥.