liquidhaskell-0.8.6.0: tests/pos/T1223.hs
{-@ LIQUID "--exactdc" @-}
{-@ LIQUID "--higherorder" @-}
{-@ LIQUID "--ple-local" @-}
{-@ infix ++ @-}
module Reverse where
import Prelude hiding (reverse, (++))
data Defined = Defined
infixl 2 ^^^
x ^^^ Defined = x
infixl 3 ==., ?
x ? _ = x
(==.) :: a -> a -> a
_ ==. x = x
-------------------------------------------------------------------------------
-- | Specification of reverse' ------------------------------------------------
-------------------------------------------------------------------------------
{-@ specReverse' :: xs:[a] -> ys:[a] -> {reverse' xs ys = reverse xs ++ ys} @-}
specReverse' :: [a] -> [a] -> ()
specReverse' _ _ = undefined
-------------------------------------------------------------------------------
-- | Derivation of reverse' ---------------------------------------------------
-------------------------------------------------------------------------------
-- LH TODO: LH is not letting you define a measure and a Haskell function
-- with the same name, for now...
{-@ measure reverse' :: [a] -> [a] -> [a] @-}
reverse' :: [a] -> [a] -> [a]
{-@ reverse' :: xs:[a] -> ys:[a] -> { reverse' xs ys = reverse xs ++ ys } @-}
reverse' [] ys
= reverse [] ++ ys
==. [] ++ ys ? specReverse' [] ys
==. ys
^^^ Defined
reverse' (x:xs) ys
= reverse (x:xs) ++ ys
==. (reverse xs ++ [x]) ++ ys ? specReverse' (x:xs) ys
==. reverse xs ++ ([x] ++ ys) ? assoc (reverse xs) [x] ys
==. reverse xs ++ (x:ys)
==. reverse' xs (x:ys)
^^^ Defined
-------------------------------------------------------------------------------
-- | Helpers: Definitions & Theorems Used -------------------------------------
-------------------------------------------------------------------------------
{-@ reflect reverse @-}
reverse :: [a] -> [a]
reverse [] = []
reverse (x:xs) = reverse xs ++ [x]
{-@ reflect ++ @-}
(++) :: [a] -> [a] -> [a]
[] ++ ys = ys
(x:xs) ++ ys = x:(xs ++ ys)
{-@ automatic-instances assoc @-}
{-@ assoc :: xs:[a] -> ys:[a] -> zs:[a]
-> { xs ++ (ys ++ zs) == (xs ++ ys) ++ zs } @-}
assoc :: [a] -> [a] -> [a] -> ()
assoc [] _ _ = ()
assoc (x:xs) ys zs = assoc xs ys zs