% Higher Order Specifications
Higher Order Specifications
---------------------------
\begin{code}
module Loop where
{-@ LIQUID "--no-termination"@-}
\end{code}
Higher Order Specifications
---------------------------
Consider a `loop` function:
\begin{code}
loop :: Int -> Int -> a -> (Int -> a -> a) -> a
loop lo hi base f = go lo base
where
go i acc | i < hi = go (i+1) (f i acc)
| otherwise = acc
\end{code}
LiquidHaskell **infers**
- if `lo <= hi` then `f` called with `lo <= i < hi`
Higher Order Specifications
---------------------------
Lets use `(!!)` to write a function that sums an `Int` list
\begin{code}
{-@ listSum :: [Int] -> Int @-}
listSum :: [Int] -> Int
listSum xs = loop 0 n 0 body
where
body = \i acc -> acc + (xs !! i)
n = length xs
\end{code}
By **function subtyping** LiquidHaskell **infers**
- `body` called with `0 <= i < llen xs`
- hence, indexing safe.
Demo:
Let's change the `0` to `-1` and see what happens!
Higher Order Specifications
---------------------------
We can give this function a better type:
\begin{code}
{-@ listNatSum :: [Nat] -> Nat @-}
listNatSum :: [Int] -> Int
listNatSum xs = loop 0 n 0 body
where
body = \i acc -> acc + (xs !! i)
n = length xs
\end{code}
To verify this type, note: `(+) :: Nat -> Nat -> Nat`
LiquidHaskell **instantiates** `a` in `loop` with `Nat`
- `loop :: Int -> Int -> Nat -> (Int -> Nat -> Nat) -> Nat`
Yielding the output.
Higher Order Specifications
---------------------------
By the same analysis, LiquidHaskell verifies that
\begin{code}
{-@ listEvenSum :: [Even] -> Even @-}
listEvenSum :: [Int] -> Int
listEvenSum xs = loop 0 n 0 body
where body = \i acc -> acc + (xs !! i)
n = length xs
\end{code}
Here, the system deduces that `(+)` has type
- `x:Int-> y:Int -> {v:Int| v=x+y} <: Even -> Even -> Even`
Hence, verification proceeds by *instantiating* `a` with `Even`
- `loop :: Int -> Int -> Even -> (Int -> Even -> Even) -> Even`
Another Example
---------------
Consider a simpler example:
\begin{code}
{-@ add :: n:Nat -> m:Nat -> {v:Int| v = m + n} @-}
add :: Int -> Int -> Int
add n m = loop 0 m n (\_ i -> i + 1)
\end{code}
Cannot use parametric polymorphism as before!
- Cannot instantiate `a` with `{v:Int|v = n + m}` ...
- ... as this only holds after **last iteration** of loop!
Require Higher Order Invariants
- On values computed in **intermediate** iterations...
- ... i.e. invariants that **depend on the iteration index**.