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 P
Now 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 x
Now 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 ⊥.
I was experimenting a bit with the
assertfunction that I added in #388 for enforcing dynamic contracts. In particular, I wanted to implement the following function:Now 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}} → ais defined as usual byit {{x}} = x). This leads to the expected Haskell code:However I realized I could also put the
assertin 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
assertfunction 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
assertis logically inconsistent because you can always simplyassert ⊥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 usingpostulatein the definition ofassertit should work more like the definition oferrorwhich requires a tactic argument of type⊥.