liquidhaskell-0.8.2.0: docs/slides/BOS14/lhs/03_HigherOrderFunctions.lhs
{#hofs}
=========
<div class="hidden">
\begin{code}
module Loop (
listSum
, sumNats
) where
import Prelude
{-@ LIQUID "--no-termination"@-}
sumNats :: [Int] -> Int
add :: Int -> Int -> Int
\end{code}
</div>
Higher-Order Functions
----------------------
Types scale to *Higher-Order Functions*
<br>
<div class="fragment">
+ map
+ fold
+ visitors
+ callbacks
+ ...
</div>
<br>
<div class="fragment">Difficult with *first-order program logics*</div>
Higher Order Specifications
===========================
Example: Higher Order Loop
--------------------------
<br>
\begin{code}
loop :: Int -> Int -> α -> (Int -> α -> α) -> α
loop lo hi base f = go lo base
where
go i acc
| i < hi = go (i+1) (f i acc)
| otherwise = acc
\end{code}
<br>
By subtyping, we infer `f` called with values `(Btwn lo hi)`
Example: Summing Lists
----------------------
\begin{code}
listSum xs = loop 0 n 0 body
where
body i acc = acc + (xs !! i)
n = length xs
\end{code}
<br>
<div class="fragment">
**Function Subtyping**
\begin{spec}
loop :: l -> h -> α -> (Btwn l h -> α -> α) -> α
\end{spec}
</div>
<br>
<div class="fragment">
At callsite, since `l := 0` and `h := llen xs`
\begin{spec}
body :: Btwn 0 (llen xs) -> Int -> Int
\end{spec}
</div>
Example: Summing Lists
----------------------
\begin{spec}
listSum xs = loop 0 n 0 body
where
body i acc = acc + (xs !! i)
n = length xs
\end{spec}
<br>
**Function Subtyping**
\begin{spec}
body :: Btwn 0 (llen xs) -> Int -> Int
\end{spec}
<br>
So `i` is `Btwn 0 (llen xs)`; indexing `!!` is verified safe.
{#polyinst}
============
Polymorphic Instantiation
-------------------------
<br>
<br>
<br>
<div class="fragment">
"Plugging in" summaries at call-sites
</div>
Polymorphic Instantiation
=========================
{#poly}
--------
Example: Summing `Nat`s
-----------------------
\begin{code}
{-@ sumNats :: [Nat] -> Nat @-}
sumNats xs = foldl (+) 0 xs
\end{code}
<br>
<div class="fragment">
\begin{spec} Recall
foldl :: (α -> β -> α) -> α -> [β] -> α
\end{spec}
</div>
<br>
<div class="fragment">
How to **instantiate** `α` and `β` ?
</div>
Function Subtyping
------------------
\begin{spec}<div/>
(+) :: x:Int -> y:Int -> {v:Int|v=x+y}
<: Nat -> Nat -> Nat
\end{spec}
<br>
<div class="fragment">
Because,
\begin{spec}<div/>
|- Nat <: Int -- Contra (in)
x:Nat, y:Nat |- {v = x+y} <: Nat -- Co (out)
\end{spec}
</div>
<br>
<div class="fragment">
Because,
\begin{spec}<div/>
0<=x && 0<=y && v = x+y => 0 <= v
\end{spec}
</div>
Example: Summing `Nat`s
-----------------------
\begin{spec} <div/>
{-@ sumNats :: [Nat] -> Nat @-}
sumNats xs = foldl (+) 0 xs
\end{spec}
<br>
\begin{spec} Where:
foldl :: (α -> β -> α) -> α -> [β] -> α
(+) :: Nat -> Nat -> Nat
\end{spec}
<br>
<div class="fragment">
Hence, `sumNats` verified by **instantiating** `α,β := Nat`
</div>
<br>
<div class="fragment">
`α` is **loop invariant**, instantiation is invariant **inference**
</div>
Instantiation And Inference
---------------------------
Polymorphism ubiquitous, so inference is critical!
<br>
<div class="fragment">
**Step 1. Templates**
Instantiate with unknown refinements
$$
\begin{array}{rcl}
\alpha & \defeq & \reft{v}{\Int}{\kvar{\alpha}}\\
\beta & \defeq & \reft{v}{\Int}{\kvar{\beta}}\\
\end{array}
$$
</div>
<br>
<div class="fragment">
**Step 2. Horn-Constraints**
By type checking the templates
</div>
<br>
<div class="fragment">
**Step 3. Fixpoint**
Abstract interpretation to get solution for $\kvar{}$
</div>
Iteration Dependence
--------------------
**Problem:** Cannot use parametric polymorphism to verify
<br>
\begin{code}
{-@ add :: n:Nat -> m:Nat -> {v:Nat|v=m+n} @-}
add n m = loop 0 m n (\_ i -> i + 1)
\end{code}
<br>
<div class="fragment">
As property only holds after **last iteration** ...
<br>
... cannot instantiate $\alpha \defeq \reft{v}{\Int}{v = n + m}$
</div>
<br>
<div class="fragment">
**Problem:** *Iteration-dependent* invariants...? [[Continue]](04_AbstractRefinements.lhs.slides.html)
</div>