packages feed

liquidhaskell-0.8.10.7: docs/slides/NEU14/00_Refinements.hs

{-@ LIQUID "--short-names"    @-}
{-@ LIQUID "--no-warnings"    @-}
{-@ LIQUID "--diffcheck"    @-}
{-@ LIQUID "--no-termination" @-}

module Refinements where

import Prelude hiding (map, foldr, foldr1)


wtAverage :: List (Int, Int) -> Int


-----------------------------------------------------------------------
-- | 1. Simple Refinement Types
-----------------------------------------------------------------------

{-@ type Nat = {v:Int | v >= 0} @-}
{-@ type Pos = {v:Int | v >  0} @-}


-----------------------------------------------------------------------
-- | 2. Function Contracts: Preconditions & Dead Code 
-----------------------------------------------------------------------

{-@ dead :: {v:_ | false} -> a @-}
dead msg = error msg

-----------------------------------------------------------------------
-- | 3. Function Contracts: Safe Division 
-----------------------------------------------------------------------



{-@ divide :: _ -> {v:_ | v > 0 } -> Int @-}
divide     :: Int -> Int -> Int
divide x 0 = dead 12  -- "divide-by-zero"
divide x n = x `div` n



-----------------------------------------------------------------------
-- | 4. Dividing Safely
-----------------------------------------------------------------------



-----------------------------------------------------------------------
-- | 4. Data Types
-----------------------------------------------------------------------

data List a = N | C a (List a)

infixr 9 `C`

 
-----------------------------------------------------------------------
-- | 4. Measuring the Size of Data
-----------------------------------------------------------------------

{-@ measure size @-}
size          :: List a -> Int
size (C x xs) = 1 + size xs 
size N        = 0

-- data List a where
--   N :: forall a. {v: List a | size v = 0}
--   C :: forall a. x:a -> xs:List a -> {v: List a | size v = 1 + size xs}
                
-----------------------------------------------------------------------
-- | 5. A few Higher-Order Functions
-----------------------------------------------------------------------

{-@ map              :: (a -> b) -> xs:List a -> {v: List b | size v = size xs} @-}
map f (N)            = N
map f (C x xs)       = C (f x) (map f xs) 

{-@ foldr1           :: (a -> a -> a) -> {v: List a | 0 < size v } -> a @-}
foldr1 f (C x xs)    = foldr f x xs
foldr1 f N           = dead "foldr1"

foldr f acc N        = acc
foldr f acc (C x xs) = f x (foldr f acc xs)
 

-----------------------------------------------------------------------
-- | 5. Weighted-Averages 
-----------------------------------------------------------------------

{-@ wtAverage :: {v : List (Pos, Pos) | size v > 0} -> Int @-}
wtAverage wxs = total `divide` weights
  where
    total     = sum $ map (\(w, x) -> w * x) wxs
    weights   = sum $ map (\(w, _) -> w    ) wxs
    sum       = foldr1 (+)


-- | Exercise: How would you modify the types to get output `Pos` above? 

-----------------------------------------------------------------------
-- | 5. Ordered Lists: Take 1
-----------------------------------------------------------------------

{- data List a = N | C {x :: a, xs :: List {v:a | x <= v}} @-}

okList :: List Int
okList = 1 `C` 2 `C` 4 `C` N

-- Note that adding ordering BREAKS `map`...



{-@ insert         :: _ -> xs:_ -> {v:_ | size v = 1 + size xs} @-}
insert x N         = x `C` N
insert x (C y ys)
  | x <= y         = x `C` y `C` ys
  | otherwise      = y `C` insert x ys 




{-@ insertSort     :: (Ord a) => xs:[a] -> {v:List a | size v = len xs} @-}
insertSort []      = N
insertSort (x:xs)  = insert x (insertSort xs)