packages feed

liquidhaskell-0.8.2.0: docs/slides/BOS14/hs/end/001_Refinements.hs

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

module Refinements where

import Prelude hiding (map, foldr, foldr1)

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

-----------------------------------------------------------------------
-- | Our first Data Type
-----------------------------------------------------------------------

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

infixr 9 `C`

-----------------------------------------------------------------------
-- | A few Higher-Order Functions
-----------------------------------------------------------------------

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


foldr                :: (a -> b -> b) -> b -> List a -> b 
foldr f acc N        = acc
foldr f acc (C x xs) = f x (foldr f acc xs)


-- Uh oh. How shall we fix the error? Lets move on for now...

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


-----------------------------------------------------------------------
-- | 6. Weighted-Averages 
-----------------------------------------------------------------------

-- Yikes, a divide-by-zero. How shall we fix it?
{-@ 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? 





 
-----------------------------------------------------------------------
-- | Measuring the Size of Data
-----------------------------------------------------------------------

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


{-@ append :: xs:_ -> ys:_ -> {v: _ | size v = size ys + size xs} @-}
append N        ys = ys
append (C x xs) ys = C x (append xs ys)


-----------------------------------------------------------------------
-- | But there are limitations: why does this not work? ...
-----------------------------------------------------------------------

{-@ append' :: xs:_ -> ys:_ -> {v: _ | size v = size xs + size ys} @-}
append' xs ys =  foldr C ys xs




-----------------------------------------------------------------------
-- | Definitions from 000_Refinements.hs
-----------------------------------------------------------------------

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

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

{-@ divide :: Int -> NonZero -> Int @-}
divide x 0 = dead "divide-by-zero"
divide x n = x `div` n