{-@ LIQUID "--short-names" @-}
{-@ LIQUID "--no-warnings" @-}
{-@ LIQUID "--no-termination" @-}
module Sort where
import Prelude hiding (sum, length, map, filter, foldr, foldr1)
import qualified Data.Set as S -- hiding (elems, insert)
-- insert, insertE :: (Ord a) => a -> [a] -> [a]
-- sort, sortE :: (Ord a) => [a] -> [a]
Invariants of Data Structures
So far
Properties of basic values
e.g. {v:Int | lo <= v && v < hi}
Properties of structures
e.g. {v:[Int] | length v == 1 + length xs}
Invariants of Data Structures
So far
Properties of basic values
e.g. {v:Int | lo <= v && v < hi}
Properties of structures
e.g. {v:[Int] | length v == 1 + length xs}
Next
Invariants of structures
e.g. a Date
is valid or a List
is sorted
Recall: Properties of Structures
Refined Constructor Types
[] :: {v:[a] | length v = 0}
(:) :: a -> t:[a] -> {v:[a] | length v = 1 + length t}
Recall: Properties of Structures
Refined Constructor Types
[] :: {v:[a] | length v = 0}
(:) :: a -> t:[a] -> {v:[a] | length v = 1 + length t}
Generalize Properties during Construction
i.e. applying type of []
and (:)
Instantiate Properties during Pattern-Matching
i.e. unapplying type of []
and (:)
Strategy: Encode Invariants in Constructors
Reuse the idea for properties!
Verification works out exactly as before
Strategy: Encode Invariants in Constructors
Reuse the idea for properties!
Verification works out exactly as before
Generalize Invariant during Construction
i.e. applying type of []
and (:)
Instantiate Invariant during Pattern-Matching
i.e. unapplying type of []
and (:)
Invariant: Ordered Pairs
Lets write a type for ordered pairs
data OrdPair = OP {opX :: Int, opY :: Int}
-- | Constructing Pairs
okPair = OP 2 4 -- legal
badPair = OP 4 2 -- illegal
-- | Destructing Pairs
checkPair (OP a b)
| a < b = True
| otherwise = impossible "illegal OrdPair!"
-- | Refine `OrdPair` to only allow legal pairs where opX < opY
{-@ data OrdPair = OP { opX :: Int, opY :: Int} @-}
Exercise: Refine OrdPair
to only allow legal pairs where opX < opY
Invariant via Refined Constructors
Reuse Strategy: Refinements Strengthen Constructors!
OP :: opX:Int -> opY:{v:Int|opX < v} -> OrdPair
Invariant via Refined Constructors
Reuse Strategy: Refinements Strengthen Constructors!
OP :: opX:Int -> opY:{v:Int|opX < v} -> OrdPair
Invariant Checked At Construction
By applying constructor pre-condition
Invariant via Refined Constructors
Reuse Strategy: Refinements Strengthen Constructors!
OP :: opX:Int -> opY:{v:Int|opX < v} -> OrdPair
Invariant Checked At Construction
By applying constructor pre-condition
Invariant Instantiated At Pattern-Matching
By unapplying constructor pre-condition
Refined Data: CSV Tables
A datatype to represent Comma-Separated-Value Tables
data Csv = Csv { hdrs :: [String]
, rows :: [[Int]]
}
scores = Csv
{ hdrs = ["Id", "Midterm", "Final"]
, rows = [[ 1 , 25 , 88]
,[ 2 , 27 , 83]
,[ 3 , 19 , 93]]
}
Exercise: Legal CSV Tables
A Legal CSV table has rows without missing values
badScores = Csv
{ hdrs = ["Id", "Midterm", "Final"]
, rows = [[ 1 , 88]
,[ 2 , 27 , 83]
,[ 3 , 19 ]]
}
{-@ data Csv = Csv { hdrs :: [String]
, rows :: [[Int]]
}
@-}
Exercise: Refine Csv
so badScores
is rejected.
Ordered Lists
Define a list type whose legal values are ordered
Ordered Lists
Define a list type whose legal values are ordered
data OList a = Emp
| (:<) { oHd :: a, oTl :: OList a }
okList :: OList Int
okList = 1 :< 2 :< 3 :< Emp -- legal
badList :: OList Int
badList = 1 :< 3 :< 2 :< Emp -- illegal
{-@ data OList a = Emp
| (:<) {oHd :: a, oTl :: OList a}
@-}
Exercise: Refine OList
so (only) badList
is rejected.
Recap: Invariant via Refined Constructors
OP :: opX:Int -> opY:{v:Int |opX < v} -> OrdPair
Csv :: hdrs:[String] -> [{row:[Int]|len row = len hdrs}] -> Csv
Emp :: OList a
(:<) :: oHd:a -> OList {v:a |oHd < v} -> OList a
Recap: Invariant via Refined Constructors
OP :: opX:Int -> opY:{v:Int |opX < v} -> OrdPair
Csv :: hdrs:[String] -> [{row:[Int]|len row = len hdrs}] -> Csv
Emp :: OList a
(:<) :: oHd:a -> OList {v:a |oHd < v} -> OList a
Invariant Checked at Construction and Instantiated at Pattern-Matching
Simply by applying and un-applying refined constructor type!