## New Syntax for Abstract Refinements ### Ghost Parameters ```haskell A n -> B (n + 1) -- becomes { p n => q (n + 1)}. A

-> B -- i.e. { p n => v = n + 1 => q v}. A

-> B ``` which means, I suppose that ```haskell A n -> B (op n) -- becomes { p n => q (op n) }. A

-> B -- i.e. { p n => v = op n => q v }. A

-> B ``` (a -> Count b <

>) -> xs:List a -> (Count (List b) <>) ```haskell A n -> B m -> C (n + m) -- becomes { p n => q m => r (n + m) }. A

-> B -> C -- i.e. { p n => q m => v = n + m => r v }. A

-> B -> C ``` { n::Int

|- {v:Int | v = n+1} <: Int } ```haskell {-@ bump1 :: forall Bool, q::Int -> Bool>. { n::Int

|- {v:Int | v = n + 1} <: Int } (Int -> Int

) -> Int @-} bump1 :: (Int -> Int) -> Int bump1 f = f 0 + 1 {-@ bumps :: forall Bool, q::Int -> Bool>. { xs :: [Int]

|- {v:Int | v = len xs} <: Int } (Int -> [Int]

) -> Int @-} bumps :: (Int -> ListN Int n) -> IntN n bumps f = size (f 0) {-@ bump2 :: forall Bool, q::Int -> Bool, r::Int -> Bool>. { n::Int

, m::Int |- {v:Int | v = n + m} <: Int } (Int -> Int

) -> (Int -> Int) -> Int @-} bump2 :: (Int -> Int) -> (Int -> Int) -> Int bump2 f g = f 0 + g 0 {-@ flerb :: ({v:Int | v = 6}, {v:Int | v = 10}) @-} flerb = (a, b) where a = bump zong b = bump2 zong zong zong :: Int -> Int zong n = 5 {-@ type IntN N = {v:Int | v == N} @-} bump1 :: Ghost n. (Int -> IntN n) -> IntN (n+1) bump2 :: Ghost n m. (Int -> IntN n) -> (Int -> IntN m) -> IntN (n+m) ``` ### New Proposal **NOTE:** I believe this is a **purely syntactic change**: it should not affect how absref is actually implemented, but it more precisely describes the implementation than the current `-> Bool` formulation. #### Step 1: Abstract Refinement is "Type with Shape" Key idea is to think of an abstract refinement as a (function returning a) refinement type. That is, the abstract refinement: ```haskell T1 -> T2 -> T3 -> ... -> S -> Bool ``` now just becomes ```haskell T1 -> T2 -> T3 -> ... -> {S} ``` Here, `{S}` denotes a refinement type with shape `S` **Key Payoff:** This means that we don't need an _explicit application_ form, that is ```haskell foo :: forall

Bool>. [Int

] -> Int

``` can just be written as ```haskell foo :: forall

. [p] -> p ``` where we need not write `Int

`, its enough to just write `p`. #### Step 2: An explicit "Meet" Operator However, sometimes you need to write things like: ```haskell List

a <

> ``` where `p :: List a -> Bool` i.e. `p :: {List a}` and which denotes * a list-of-a that is recursively indexed by `p`, AND * where the top-level list is constrained by `p`. That is, more generally, where you want to * additionally, index the type with other abstract refinements, AND * "apply" an abstract refinement to the "top-level" type. For this, I think we should have an explicit *meet* operator Note that, earlier `Int

` was an *implicit* meet operator, where we were *conjoining* `Int` and `p`. Viewing `p` as just being a refined `Int` allows us to SEPARATE "meet" to only those places where its really needed. So we can write the funny `List

a <

>` as: ```haskell p /\ List

a ``` See below for many other examples: #### Example: Value Dependencies **Old** ```haskell foo :: forall

Int -> Bool>. x:Int -> [Int

] -> Int

``` **New** ```haskell foo :: forall

{Int}>. x:Int -> [p x] -> p x ``` #### Example: Dependent Pairs **Old** ```haskell data Pair a b

b -> Bool> = Pair { pairX :: a , pairB :: b

} type OrdPair a = Pair <{\px py -> px < py}> a a ``` **New** ```haskell data Pair a b

{b}> = Pair { pairX :: a , pairY :: p pairX } type OrdPair a = Pair a a <\px -> {py:a | px < py}> ``` #### Example: Binary Search Maps **Old** ```haskell data Map k a k -> Bool, r :: root:k -> k -> Bool> = Tip | Bin { mSz :: Size , mKey :: k , mValue :: a , mLeft :: Map (k ) a , mRight :: Map (k ) a } type OMap k a = Map <{\root v -> v < root }, {\root v -> v > root}> k a ``` **New** ```haskell data Map k a {k}, r :: root:k -> {k}> = Tip | Bin { mSz :: Size , mKey :: k , mValue :: a , mLeft :: Map (l mKey) a , mRight :: Map (r mKey) a } type OMap k a = Map k a <\root -> {v:k | v < root }, \root -> {v:k | root < v}> ``` #### Example: Ordered Lists **Old** ```haskell data List a

a -> Bool> = Emp | Cons { lHd :: a , lTl :: List

(a

) } type OList a = List <{\x v -> x <= v}> a ``` **New** ```haskell data List a

{a}> = Emp | Cons { lHd :: a , lTl :: List (p lHd)

} type OList a = List a <\x -> {v:a | x <= v}> ``` #### Example: Infinite Streams **Old** ```haskell data List a

Prop> = N | C { x :: a , xs :: List

a <

> } type Stream a = {xs: List <{\v -> isCons v}> a | isCons xs} ``` **New** ```haskell data List a

= N | C { x :: a , xs :: p /\ List a

} type Stream a = {xs: List a <{v | isCons v}> | isCons xs} ``` ### Old Proposal | | Current Syntax | Future Syntax | |----------------------|-------------------------------|-------------------------------| | Abstract Refinements | `List <{\x v -> v >= x}> Int` | `List Int (\x v -> v >= x)` | | | `[a

]<{\x v -> v >= x}>` | `[a p] (\x v -> v >= x) (??)` | | | `Int

` | `Int p` | | | `Int<\x -> x >=0>` | `Int (\x -> x >= 0)` | | | `Maybe <

> (a) (?)` | `Maybe (a q) p` | | | `Map <

> k v (?)` | `Maybe k v l r p` | | Type Arguments | `ListN a {len xs + len ys}` | `ListN a (len xs + len ys)` | Q: How do I distinguish `Int p` with `ListN a n`? (`p` is a abstract refinement and `n` is an `Integer`) A: From the context! Use simple kinds, i.e. `ListN :: * -> Int -> *` `Int :: ?AR -> *`