Reasoning steps with inequality
josedusol opened this issue · comments
Hello. Module Equational
provides the ==.
operator to do equational reasoning. What about inequaility?.
For example, suppose we want to prove something like:
{-@ filterLength :: p:(a -> Bool) -> l:List a -> { length (filter p l) <= length l } @-}
Then the reasoning chain would involve ==.
steps but also "<=" steps. Is this possible?
Hi! Odd -- there certainly used to be -- see these:
liquidhaskell/tests/benchmarks/popl18/lib/Proves.hs
Lines 101 to 117 in 369a7a6
I think you can just write your own following that template.
So
{-@ (<=.) :: x:a -> y:{a | x <= y} -> {v:a | v == y} @-}
(<=.) :: a -> a -> a
_ ==. y = y
{-# INLINE (<=.) #-}
Thanks @ranjitjhala . But unfortunately, i can't use the proof combinator with an intermediate justification:
module Test where
import Language.Haskell.Liquid.Equational
import Prelude hiding (length,filter)
{-@ (<=.) :: x:a -> y:{a | x <= y} -> {v:a | v == x} @-}
(<=.) :: a -> a -> a
x <=. y = x
{-# INLINE (<=.) #-}
{-@ reflect length @-}
{-@ length :: [a] -> Int @-}
length :: [a] -> Int
length = \l -> case l of { [] -> 0; x:xs -> length xs + 1 }
{-@ reflect filter @-}
{-@ filter :: (a -> Bool) -> [a] -> [a] @-}
filter :: (a -> Bool) -> [a] -> [a]
filter = \p l -> case l of { [] -> []; x:xs -> case p x of { False -> filter p xs; True -> x:filter p xs }}
{-@ assume leqZero :: n:Nat -> { 0 <= n } @-}
leqZero :: Int -> Proof
leqZero n = ()
{-@ filterLength :: p:(a -> Bool) -> l:[a] -> { length (filter p l) <= length l } @-}
filterLength :: (a -> Bool) -> [a] -> Proof
filterLength p [] =
length (filter p [])
? filter p []
==. length []
? length []
==. 0
? leqZero (length []) -- TYPE ERROR if present
<=. length []
*** QED
filterLength p (x:xs) = undefined
The intermediate justification ? leqZero (length [])
raises
error:
* Couldn't match type `Int' with `()'
Expected: Proof
Actual: Int
* In the second argument of `(<=.)', namely `length []'
In the second argument of `(?)', namely
`leqZero (length []) <=. length []'
In the first argument of `(***)', namely
`length (filter p []) ? filter p [] ==. length [] ? length [] ==. 0
? leqZero (length []) <=. length []'
|
37 | <=. length []
From my understanding, the justification should be optional just like in ==.
, but sometimes it may be neccesary.
Ah that's just a matter of the "parsing/precedence" see this
http://goto.ucsd.edu:8090/index.html#?demo=permalink%2F1694706430_580.hs
in fact, adding
infixl 3 <=.
to the file makes it work directly.
http://goto.ucsd.edu:8090/index.html#?demo=permalink%2F1694706535_584.hs