Abstract Refinements {#composition} =================================== Very General Mechanism ---------------------- **Next:** Lets add parameters... Example: `plus` --------------- \begin{code} {-@ plus :: x:_ -> y:_ -> {v:_ | v=x+y} @-} plus x y = x + y \end{code} Example: `plus 3` -----------------
\begin{code} {-@ plus3' :: x:Int -> {v:Int | v = x + 3} @-} plus3' = plus 3 \end{code}
Easily verified by LiquidHaskell A Composed Variant ------------------ Lets define `plus3` by *composition* A Composition Operator ---------------------- \begin{code} (#) :: (b -> c) -> (a -> b) -> a -> c (#) f g x = f (g x) \end{code} `plus3` By Composition ----------------------- \begin{code} {-@ plus3'' :: x:Int -> {v:Int | v = x + 3} @-} plus3'' = plus 1 # plus 2 \end{code}
Yikes! Verification *fails*. But why?
(Hover mouse over `#` for a clue)
How to type compose (#) ? ------------------------- This specification is *too weak*
\begin{spec}
(#) :: (b -> c) -> (a -> b) -> (a -> c) \end{spec}
Output type does not *relate* `c` with `a`! How to type compose (.) ? ------------------------- Write specification with abstract refinement type:
\begin{code} {-@ (.) :: forall

c->Prop, q :: a->b->Prop>. f:(x:b -> c

) -> g:(x:a -> b) -> y:a -> exists[z:b].c

@-} (.) f g y = f (g y) \end{code} Using (.) Operator ------------------
\begin{code} {-@ plus3 :: x:Int -> {v:Int | v = x + 3} @-} plus3 = plus 1 . plus 2 \end{code}

*Verifies!*
Using (.) Operator ------------------ \begin{spec}
{-@ plus3 :: x:Int -> {v:Int | v = x + 3} @-} plus3 = plus 1 . plus 2 \end{spec}
LiquidHaskell *instantiates* - `p` with `\x -> v = x + 1` - `q` with `\x -> v = x + 2` Using (.) Operator ------------------ \begin{spec}
{-@ plus3 :: x:Int -> {v:Int | v = x + 3} @-} plus3 = plus 1 . plus 2 \end{spec}
To *infer* that output of `plus3` has type: `exists [z:{v = y + 2}].{v = z + 1}`
`<:` `{v:Int|v=3}`
Recap ----- 1. **Refinements:** Types + Predicates 2. **Subtyping:** SMT Implication 3. **Measures:** Strengthened Constructors 4. **Abstract:** Refinements over Type Signatures +
*Dependencies* using refinement parameters