{-@ LIQUID "--short-names" @-} {-@ LIQUID "--no-warnings" @-} {-@ LIQUID "--no-termination" @-} {-@ LIQUID "--smtsolver=cvc4" @-} module Refinements where import Prelude hiding (abs) divide :: Int -> Int -> Int ----------------------------------------------------------------------- -- | Simple Refinement Types ----------------------------------------------------------------------- {-@ six :: {v:Int | v = 6} @-} six = 6 :: Int ----------------------------------------------------------------------- -- | Type Aliases are nice, we're gonna be liberal in our use of them ----------------------------------------------------------------------- {-@ type Nat = {v:Int | v >= 0} @-} {-@ type Pos = {v:Int | v > 0} @-} {-@ type NonZero = {v:Int | v /= 0} @-} ----------------------------------------------------------------------- -- | Subtyping via Implication ----------------------------------------------------------------------- {-@ six' :: NonZero @-} six' = six -- {v:Int | v = 6} <: {v:Int | v /= 0} -- ==> -- v = 6 => v /= 0 ----------------------------------------------------------------------- -- | Function Contracts: Preconditions & Dead Code ----------------------------------------------------------------------- {-@ die :: {v:_ | false} -> a @-} die msg = error msg -- Precondition says, there are **NO** valid inputs for @die@. -- If program type-checks, means @die@ is **NEVER** called at run-time. ----------------------------------------------------------------------- -- | Function Contracts: Safe Division ----------------------------------------------------------------------- divide x 0 = die "divide-by-zero" divide x n = x `div` n -- | What's the problem above? Nothing to *prevent* -- us from calling `divide` with 0. Oops. -- How shall we fix it? avg2 x y = divide (x + y) 2 avg3 x y z = divide (x + y + z) 3 ----------------------------------------------------------------------- -- | But whats the problem here? ----------------------------------------------------------------------- avg xs = divide total n where total = sum xs n = length xs -------------------------------------------------------------- -- | CHEAT AREA ---------------------------------------------- -------------------------------------------------------------- -- # START Errors 1 (divide) -- # END Errors 1 (avg) {- divide :: Int -> NonZero -> Int @-}