packages feed

liquidhaskell-0.8.2.0: docs/slides/niki/lhs/Composition.lhs

% Function Composition

Function Composition
--------------------

\begin{code}
module Composition where
\end{code}

A Plus Function
---------------

Consider a simple `plus` function 

\begin{code}
{-@ plus :: x:Int -> y:Int -> {v:Int | v = x + y} @-}
plus     :: Int -> Int -> Int
plus x y = x + y
\end{code}

A Simple Addition 
-----------------

Consider a simple use of `plus` a function that adds `3` to its input:

\begin{code}
{-@ plus3' :: x:Int -> {v:Int | v = x + 3} @-}
plus3'     :: Int -> Int
plus3' x   = x + 3
\end{code}

- The refinement type captures its behaviour...

- ... and LiquidHaskell easily verifies this type.

A Composed Variant
------------------

Instead, suppose we defined the previous function by composition 

We first add `2` to the argument and then add `1` to the intermediate result...

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

but verification **fails** as we need a way to **compose** the refinements!

**Problem** What is a suitable description of the compose operator

\begin{code} _ 
(.) :: (b -> c) -> (a -> b) -> (a -> c)
\end{code}

that lets us **relate** `a` and `c` via `b` ?



Composing Refinements, Abstractly
---------------------------------

- We can analyze the *composition* operator

- With a very *descriptive* abstract refinement type!

\begin{code}

{-@ cc :: forall < p :: b -> c -> Prop
                , q :: a -> b -> Prop>.
         f:(x:b -> c<p x>) 
      -> g:(x:a -> b<q x>) 
      -> y:a 
      -> exists[z:b<q y>].c<p z>
 @-}

cc :: (b -> c) -> (a -> b) -> a -> c
cc f g x = f (g x)
\end{code}

Using Composition
-----------------

We can verify the desired `plus3` function:

\begin{code}
{-@ plus3 :: x:Int -> {v:Int | v = x + 3} @-}
plus3     :: Int -> Int
plus3     = (+ 1) `cc` (+ 2)
\end{code}

LiquidHaskell verifies the above, by **instantiating**

- `p` with `v = x + 1`
- `q` with `v = x + 2`

which lets it infer that the output of `plus3` has type:

- `exists [z:{v=y+2}]. {v = z + 1}`

which is a subtype of `{v:Int | v = 3}`