Liquid Type Inference under the Hood Micha Reiser Seminar Program Analysis & Transformation University of Applied Sciences Rapperswil 1
Motivation Liquid Type Inference Conclusion 2
Motivation
Motivation for Liquid Types • Proof fine-granular invariants 3
Motivation for Liquid Types • Proof fine-granular invariants • . . . by using Dependent Types 3
Motivation for Liquid Types • Proof fine-granular invariants • . . . by using Dependent Types • . . . but with Type Inference The more interesting your types get, the less fun it is to write them down [1]. - Benjamin Pierce 3
The List-Average Example avg :: [Int] -> Int avg xs = total `div` n where total = sum xs n = length xs main = do putStrLn "Enter List" list <- readLn putStrLn ("The Avg is: " ++ (show (avg list))) 4
What can possibly go wrong, it is too easy! ./avglist Enter List [1, 5, 10] The Avg is: 5 5
Quite a Lot. . . ./avglist Enter List [] avglist: divide by zero 6
Liquid Haskell Catches these Errors for You avglist.hs:2:10-22: Error: Liquid Type Mismatch 2 | avg xs = total `div` n ^^^^^^^^^^^^^ Inferred type VV : {VV : Int | VV >= 0 && VV == len xs && VV == n} not a subtype of Required type VV : {VV : Int | VV /= 0} In Context xs : {v : [Int] | len v >= 0} n : {n : Int | n >= 0 7
Liquid Type Inference
The Goal . . . is to infer the unknown refinement predicates p of the dependent types T in the program. 8
The Structure of a Dependent Type { ν : B | p } • ν : The special value-variable • B : Base Type like int , bool , char . . . • p : The refinement predicate 9
What is a Liquid Type? A liquid type is a dependent type where the refinement predicate is a conjunction of qualifiers from Q . Q = { 0 ≤ ν, ⋆ ≤ ν, ν < ⋆ } Dependent Types (over 𝐹) Liquid Types (over ℚ ) 10
What is a Liquid Type? A liquid type is a dependent type where the refinement predicate is a conjunction of qualifiers from Q . Q = { 0 ≤ ν, ⋆ ≤ ν, ν < ⋆ } { ν : int | 0 ≤ ν } � Dependent Types (over 𝐹) Liquid Types (over ℚ ) 10
What is a Liquid Type? A liquid type is a dependent type where the refinement predicate is a conjunction of qualifiers from Q . Q = { 0 ≤ ν, ⋆ ≤ ν, ν < ⋆ } { ν : int | 0 ≤ ν } � Dependent Types (over 𝐹) { ν : int | 0 ≤ ν ∧ n ≤ ν } � Liquid Types (over ℚ ) 10
What is a Liquid Type? A liquid type is a dependent type where the refinement predicate is a conjunction of qualifiers from Q . Q = { 0 ≤ ν, ⋆ ≤ ν, ν < ⋆ } { ν : int | 0 ≤ ν } � Dependent Types (over 𝐹) { ν : int | 0 ≤ ν ∧ n ≤ ν } � Liquid Types (over ℚ ) { ν : int | ν = 0 ∧ 0 ≤ ν } ✗ 10
What is a Liquid Type? A liquid type is a dependent type where the refinement predicate is a conjunction of qualifiers from Q . Q = { 0 ≤ ν, ⋆ ≤ ν, ν < ⋆ } { ν : int | 0 ≤ ν } � Dependent Types (over 𝐹) { ν : int | 0 ≤ ν ∧ n ≤ ν } � Liquid Types (over ℚ ) { ν : int | ν = 0 ∧ 0 ≤ ν } ✗ { ν : int | 0 ≤ ν = ⇒ c ≤ ν } ✗ 10
The Approach Do you still remember these: If Alice doubles her age, she would still be 10 years younger than Bob, who was born in 1952. How old are Alice and Bob? [2] 11
The Approach Do you still remember these: If Alice doubles her age, she would still be 10 years younger than Bob, who was born in 1952. How old are Alice and Bob? [2] 1. Create Templates for the Unknown: Alice’s age: a Bob’s age: b 11
The Approach Do you still remember these: If Alice doubles her age, she would still be 10 years younger than Bob, who was born in 1952. How old are Alice and Bob? [2] 1. Create Templates for the Unknown: Alice’s age: a Bob’s age: b 2. Constraints on Templates: 2 a = b − 10 b = 2016 − 1952 11
The Approach Do you still remember these: If Alice doubles her age, she would still be 10 years younger than Bob, who was born in 1952. How old are Alice and Bob? [2] 1. Create Templates for the Unknown: Alice’s age: a Bob’s age: b 2. Constraints on Templates: 2 a = b − 10 b = 2016 − 1952 3. Solve constraints: a = 27 , b = 64 11
Let’s apply this to the sum function In Haskell sum :: Int -> Int sum n = if n < 0 then 0 else n + sum (n - 1) In L1 let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n 12
Step 1: Template Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n 13
Step 1: Template Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n n : int → int ML-Type 13
Step 1: Template Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n n : int → int ML-Type n : { ν : int | ? } → { ν : int | ? } Liquid-Type 13
Step 1: Template Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n n : int → int ML-Type n : { ν : int | ? } → { ν : int | ? } Liquid-Type n : { ν : int | κ n } → { ν : int | κ ret } Template 13
Step 1: Template Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n n : int → int ML-Type n : { ν : int | ? } → { ν : int | ? } Liquid-Type n : { ν : int | κ n } → { ν : int | κ ret } Template Definition A Liquid Type Variable κ is a placeholder for the unknown refinements 13
Two Kind Of Constraints Definition Well-Formedness Constraints define which variables can be used in a refinement predicate. Γ ⊢ T Definition Subtyping Constraints capture proof a subtyping relation between two types (and therefore, the data flow of values). Γ ⊢ T 1 < : T 2 14
Step 2: Well-Formedness Constraint Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n Template sum :: n : { ν : int | κ n } → { ν : int | κ ret } Well-Formedness Constraints: 15
Step 2: Well-Formedness Constraint Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n Template sum :: n : { ν : int | κ n } → { ν : int | κ ret } Well-Formedness Constraints: ∅ ⊢ κ n 15
Step 2: Well-Formedness Constraint Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n Template sum :: n : { ν : int | κ n } → { ν : int | κ ret } Well-Formedness Constraints: ∅ ⊢ κ n n : { ν : int | κ n } ⊢ κ ret 15
Step 2: Subtyping Constraint Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n Template sum :: n : { ν : int | κ n } → { ν : int | κ ret } The then branch flows into the result: 16
Step 2: Subtyping Constraint Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n Template sum :: n : { ν : int | κ n } → { ν : int | κ ret } The then branch flows into the result: sum : . . . , n : { ν : int | κ n } , n < 0 ⊢ { ν : int | ν = 0 } < : { ν : int | κ ret } 16
Step 2: Subtyping Constraint Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1) in s + n Template sum :: n : { ν : int | κ n } → { ν : int | κ ret } The then branch flows into the result: sum : . . . , n : { ν : int | κ n } , n < 0 ⊢ { ν : int | ν = 0 } < : { ν : int | κ ret } n : κ n , n < 0 ⊢ ν = 0 < : κ ret 16
Step 2: Subtyping Constraint Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1 ) in s + n Template sum :: n : { ν : int | κ n } → { ν : int | κ ret } n − 1 flows into the argument of sum : n : κ n , ¬ n < 0 ⊢ ν = n − 1 < : κ n 17
Step 2: Subtyping Constraint Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1 ) in s + n Template sum :: n : { ν : int | κ n } → { ν : int | κ ret } The type of sum ( n − 1) ( s ): { ν : int ⊢ κ ret [ n − 1 / n ] } 18
Step 2: Subtyping Constraint Generation let rec sum = n ⇒ if n < 0 then 0 else let s = sum ( n − 1 ) in s + n Template sum :: n : { ν : int | κ n } → { ν : int | κ ret } The else branch flows into the result n : κ n , s : κ ret [ n − 1 / n ] , ¬ n < 0 ⊢ ν = s + n < : κ ret 19
Step 2: Constraints Well-Formedness ∅ ⊢ κ n n : κ n ⊢ κ ret Subtyping n : κ n , n < 0 ⊢ ν = 0 < : κ ret n : κ n , ¬ n < 0 ⊢ ν = n − 1 < : κ n n : κ n , s : κ ret [ n − 1 / n ] , ¬ n < 0 ⊢ ν = s + n < : κ ret 20
Step 3: Solve Constraints 1. Initial assignment map A ( κ ) with all Qualifiers Q 2. Remove qualifiers that do not satisfy a constraint 21
Step 3: Solve Well-Formedness Constraints Assignment Map A ( κ ) / Current Solution κ n 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ κ ret 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ Well-Formedness Constraint ∅ ⊢ κ n n : κ n ⊢ κ ret 22
Step 3: Solve Well-Formedness Constraints Assignment Map A ( κ ) / Current Solution κ n 0 ≤ ν , ⋆ ≤ ν, ν ≤ ⋆ κ ret 0 ≤ ν, ⋆ ≤ ν, ν ≤ ⋆ Well-Formedness Constraint ∅ ⊢ κ n SAT 22
Recommend
More recommend