Subtype marks
Tamás Kozsik
[email protected]://kto.web.elte.hu/
Eötvös Loránd University, Budapest
Central-European Functional Programming SchoolEötvös Loránd University, Budapest, Hungary
4-16 July, 2005
Tamás Kozsik: Subtype Marks 2
Contents
• Context• Motivation• Intuitive description of subtype marks• Examples• Discussion
Tamás Kozsik: Subtype Marks 3
Related topics at CEFP
• Time and safety critical applications (Kevin)• Reason about programs (Máté)• Refactor programs (Simon)• Test programs (Pieter)
Tamás Kozsik: Subtype Marks 4
Fortune
“Beware of bugs in the above code; I have only proved it correct, not tried it.”
(Donald Knuth)
Tamás Kozsik: Subtype Marks 5
Aims
• Safety critical applications
• Formal proof of correctness
• Reasoning about the code
• Theorem prover + Type system
• Enyv = Egyszerű NYelV– Simple functional language
– “Subtype marks”
Tamás Kozsik: Subtype Marks 6
Proving correct
• Methodologies: formal methods– Program logics – Formal semantics
• Software development tools– Model checkers– Proof systems
• Programming languages– Alphard, Eiffel etc.
Tamás Kozsik: Subtype Marks 7
Invariant
• Widely used safety property• Temporal logics• Type invariant
– Property of legal values– Restrict the type value set
Tamás Kozsik: Subtype Marks 8
Type systems?
• Uniqueness, strictness, concurrency• Types with size information
(Kevin Hammond / Hume)• Types with shape information
(Sven Bodo Scholz / SAC)• Annotated types - invariants
(Pieter Koopman, Diederik van Arkel)• Dependent types
Tamás Kozsik: Subtype Marks 9
fac :: Int -> Int
fac 0 = 1
fac n = n * (fac (n-1))
Motivation - 1
Tamás Kozsik: Subtype Marks 10
fac :: Int -> Int
fac n = if (n<0)
(abort "Bad argument!")
(f n)
where f 0 = 1
f n = n * (f (n-1))
Motivation - 2
Tamás Kozsik: Subtype Marks 11
fac :: Int -> Int
// PRE: only for non-negative arg.
fac 0 = 1
fac n = n * (fac (n-1))
Motivation - 3
Tamás Kozsik: Subtype Marks 12
fac :: Nat -> Nat
fac 0 = 1
fac n = n * (fac (n-1))
Motivation - 4
Tamás Kozsik: Subtype Marks 13
fac :: Int{N} -> Int{N}
fac 0 = 1
fac n = n * (fac (n-1))
Motivation - 5
Tamás Kozsik: Subtype Marks 14
fac :: Int{N} -> Int{N}
fac 0 = 1
fac n = let nm1 :: Int{N!},
nm1 = n-1
in n * (fac nm1)
Motivation - 6
Tamás Kozsik: Subtype Marks 15
Enyv
• Simple functional language• Syntax: similar to that of Clean• Semantics: graph rewrite systems• Subtype marks
• Let’s see some examples…
Tamás Kozsik: Subtype Marks 16
:: List a = Nil | Cons a (List a)
Head :: List a -> aHead (Cons x xs) = x
Tail :: List a -> List aTail (Cons x xs) = xs
Append :: List a -> a -> List aAppend Nil x = Cons x NilAppend (Cons y ys) x = Cons y (Append ys x)
Reverse :: List a -> List aReverse Nil = NilReverse (Cons x xs) = Append (Reverse xs) x
Tamás Kozsik: Subtype Marks 17
Insert :: List Int -> Int -> List Int
Insert Nil e = Cons e Nil
Insert ys=:(Cons x xs) e
= If (x < e)
(Cons x (Insert xs e))
(Cons e ys)
Sort :: List Int -> List Int
Sort Nil = Nil
Sort (Cons x xs) = Insert (Sort xs) x
Tamás Kozsik: Subtype Marks 18
Insert :: List Int -> Int -> List Int
Insert Nil e = Cons e Nil
Insert (Cons x xs) e
= If (x < e)
(Cons x (Insert xs e))
(Cons e (Cons x xs))
Sort :: List Int -> List Int
Sort Nil = Nil
Sort (Cons x xs) = Insert (Sort xs) x
Tamás Kozsik: Subtype Marks 19
Expressions and functions
• Expressions– Variables– Function and data constructor symbols– Applications– Let-expressions (recursive, let-rec)
• Functions– Alternatives– Pattern matching
• No block-structure, no modules, no macros…
Tamás Kozsik: Subtype Marks 20
Types
• Algebraic type definitions• Restricted parametric polymorphism:
top-level universal quantification• No existential quantification,
no bounded polymorphism (type classes),no dynamics,no modules (no private types, no ADTs),no uniqueness,no generics
Tamás Kozsik: Subtype Marks 21
Subtype marks
• Type invariants• Annotations attached to type constructors• Richer type system• Subtype polymorphism• Connects the type system and a theorem
prover
Tamás Kozsik: Subtype Marks 22
Non-empty lists: C
C : List a ↦ {true,false}
C(xs) = (∃y,ys: xs = Cons y ys)
• Definition used by a theorem prover• Not used by the type system• “Denotational semantics for subtype marks”
Tamás Kozsik: Subtype Marks 23
Non-empty lists: C
Nil :>: List a
Cons :>: a -> List a -> List{C} a
• Definition used by the type system• Correctness proven by theorem prover• “Axiomatic semantics for subtype marks”
Tamás Kozsik: Subtype Marks 24
Sorted lists: S
Nil :>: List{S} a
Cons :>: a -> List a -> List a
• Presence of subtype mark:the value is known to have the property
• Absence of subtype mark:the value is not known to have the property
Tamás Kozsik: Subtype Marks 25
Typing functions
• Preconditions• Postconditions• Propagation of properties
Tamás Kozsik: Subtype Marks 26
Precondition
Head :: List{C} a -> a
Head (Cons x xs) = x
Tail :: List{C} a -> List a
Tail (Cons x xs) = xs
• Useful for partial functions• Not only for partial functions
Tamás Kozsik: Subtype Marks 27
Postconditions
Append :: List a -> a -> List{C} a
Append Nil x = Cons x Nil
Append (Cons y ys) x = Cons y (Append ys x)
Head (Append x xs)
Tamás Kozsik: Subtype Marks 28
Pre- and postconditions
fac :: Int{N} -> Int{N}
fac 0 = 1
fac n = let nm1 :: Int{N!},
nm1 = n-1
in n * (fac nm1)
Tamás Kozsik: Subtype Marks 29
Propagation
Reverse :: List a -> List a
Reverse :: List{C} a -> List{C} a
Reverse Nil = Nil
Reverse (Cons x xs) = Append (Reverse xs) x
• More than one type• Polymorphic notation?
Tamás Kozsik: Subtype Marks 30
Sorted lists
Tail :: List{C} a -> List a
Tail :: List{C,S} a -> List{S} a
Tail (Cons x xs) = xs
• How to type this?
Tamás Kozsik: Subtype Marks 31
Data constructors
• Composition types: expressions• Decomposition types: patterns
Cons :>: a -> List a -> List{C} a
Cons :<: a -> List a -> List{C} a
Cons :<: a -> List{S} a -> List{C,S} a
Tamás Kozsik: Subtype Marks 32
Typing Tail
Cons :<: a -> List a -> List{C} a
Cons :<: a -> List{S} a -> List{C,S} a
Tail :: List{C} a -> List a
Tail :: List{C,S} a -> List{S} a
Tail (Cons x xs) = xs
Tamás Kozsik: Subtype Marks 33
Subtype polymorphism
Tail :: List{C} a -> List a
Tail :: List{C,S} a -> List{S} a
Tail (Cons x xs) = xs
Tail :: List{C,S} a -> List a
Tail :: List{C,S,X} a -> List{S} a
...
• Weakening / subsumption
Tamás Kozsik: Subtype Marks 34
Why subtyping is needed?
Reverse (Tail (Sort (Append xs x)))
Append :: List a -> a -> List{C} aReverse :: List a -> List aReverse :: List{C} a -> List{C} aSort :: List Int -> List{S} Int Sort :: List{C} Int -> List{C,S} Int Tail :: List{C} a -> List aTail :: List{C,S} a -> List{S} a
Tail :: List{C,S} a -> List a
Tamás Kozsik: Subtype Marks 35
Variance
• Subtyping - substitution principle• Co-variant return, contra-variant arguments
Int -> Int{N} ≤ Int -> Int
Int -> Int ≤ Int{N} -> Int
Int{N} -> Int{N} ? Int -> Int
Tamás Kozsik: Subtype Marks 36
Subtyping is a partial order
• Reflexive, antisymmetric, transitive
Int -> Int{N}
Int -> Int Int{N} -> Int{N}
Int{N} -> Int
Tamás Kozsik: Subtype Marks 37
Believe-me marks
fac :: Int{N} -> Int{N}
fac 0 = 1
fac n = let nm1 :: Int{N!},
nm1 = n-1
in n * (fac nm1)
Tamás Kozsik: Subtype Marks 38
Insertion sort
Insert :: List{S} Int -> Int -> List{S!} IntInsert Nil e = Cons e NilInsert (Cons x xs) e =
If (x < e ) (Cons x (Insert xs e)) (Cons e (Cons x xs))
Sort :: List Int -> List{S} IntSort Nil = NilSort (Cons x xs) = Insert (Sort xs) x
Tamás Kozsik: Subtype Marks 39
Typing Sort
Nil :>: List{S} aInsert :: List{S} Int -> Int -> List{S!} Int
Sort :: List Int -> List{S} Int
Sort Nil = NilSort (Cons x xs) = Insert (Sort xs) x
Recursion!
Tamás Kozsik: Subtype Marks 40
Typing Insert?
Insert :: List{S} Int -> Int -> List{S!} Int
Insert Nil e = Cons e NilInsert (Cons x xs) e =
If (x < e ) (Cons x (Insert xs e)) (Cons e (Cons x xs))
• Need the formula associated to S• Need a theorem prover
Tamás Kozsik: Subtype Marks 41
Formula associated to S
• The list is sorted
Sorted Nil = True
Sorted (Cons x Nil) = True
Sorted (Cons x xs=:(Cons y ys)) =
x <= y && Sorted xs
Tamás Kozsik: Subtype Marks 42
Proving Insert correct
Insert :: List{S} Int -> Int -> List{S!} Int
Sorted(xs) → Sorted(Insert xs e)
• Sparkle
~(Sorted xs = False) -> ~(Sorted (Insert xs e) = False)
Tamás Kozsik: Subtype Marks 43
Undefined
• Cons 1 (Cons 2 (Cons 3 … • Cons 1/0 Nil• Partially undefined values - laziness• What if Sorted would be a partial function?
• Partial correctness
Tamás Kozsik: Subtype Marks 44
Polymorphic subtype marks
• Propagation of properties
Reverse :: List a -> List aReverse :: List{C} a -> List{C} a
Reverse Nil = NilReverse (Cons x xs) = Append (Reverse xs) x
• Subtype mark variable
Reverse :: List{p:C} a -> List{p:C} a
Tamás Kozsik: Subtype Marks 45
Subtype mark variables
Tail :: List{C,p:S} a -> List{p:S} a
Sort :: List{p:C} Int
-> List{p:C,S} Int
Cons :<: a -> List{p:S} a
-> List{C,p:S} a
Tamás Kozsik: Subtype Marks 46
Complex numbers
:: Complex = Cart Real Real // Cartesian
| Polar Real Real // Polar
Cart :>: Real -> Real -> Complex{Cart}
Cart :<: Real -> Real -> Complex{Cart}
Polar :>: Real -> Real -> Complex{Polar}
Polar :<: Real -> Real -> Complex{Polar}
Tamás Kozsik: Subtype Marks 47
Complex numbers: conversions
polar :: Complex -> Complex{Polar!}polar (Cart re im) = let delta = if (im<0.0) 1.0 0.0 in Polar (sqrt (re*re + im*im)) ( (atan (im/re)) + delta*Pi )polar c = c
cart :: Complex -> Complex{Cart!}cart (Polar r phi) = Cart (r * (cos phi)) (r * (sin phi))cart c = c
Tamás Kozsik: Subtype Marks 48
Complex numbers: Cartesian
addCC :: Complex{Cart} -> Complex{Cart}
-> Complex{Cart}
addCC (Cart re1 im1) (Cart re2 im2) =
Cart (re1+re2) (im1+im2)
• Similarly: subCC, mulCC, divCC
conjugate :: Complex{Cart} -> Complex{Cart}
conjugate (Cart re im) = Cart re (0.0-im)
Tamás Kozsik: Subtype Marks 49
Complex numbers: polarmulCP :: Complex{Polar} -> Complex{Polar} -> Complex{Polar}mulCP (Polar r1 phi1) (Polar r2 phi2) = Polar (r1*r2) (phi1+phi2)
• Similarly: divCP
absCP :: Complex{Polar} -> RealabsCP (Polar r phi) = r
powCP :: Complex{Polar} -> Real -> Complex(Polar)powCP (Polar r phi) x = Polar (r^x) (x*phi)
Tamás Kozsik: Subtype Marks 50
Complex numbers: full domain
addC :: Complex -> Complex -> Complex{Cart}addC c1 c2 = addCC (cart c1) (cart c2)
mulC :: Complex{p:Polar,c:Cart} -> Complex{p:Polar,c:Cart} -> Complex{p:Polar,c:Cart!}mulC (Cart re1 im1) (Cart re2 im2) = mulCC (Cart re1 im1) (Cart re2 im2)mulC c1 c2 = mulCP (polar c1) (polar c2)
Tamás Kozsik: Subtype Marks 51
Integer numbers
• Example introducing a new concept:
inequalities
• Strange algebraic representation
• Not efficient
• Enyv: built-in type Int
Tamás Kozsik: Subtype Marks 52
:: Integer = Zero | Succ Integer | Pred Integer
Add Zero y = yAdd (Succ x) y = Add x (Succ y)Add (Pred x) y = Add x (Pred y)
Minus Zero = ZeroMinus (Succ x) = Pred (Minus x)Minus (Pred x) = Succ (Minus x)
Substract x y = Add x (Minus y)
Multiply Zero y = ZeroMultiply (Succ x) y = Add (Multiply x y) yMultiply (Pred x) y = Substract (Multiply x y) y
Tamás Kozsik: Subtype Marks 53
Can and Nat
• Representation: not surjective:: Integer = Zero
| Succ Integer
| Pred Integer
• Canonical representation - Canbuilt from: Zero and (Succ xor Pred)
• Natural numbers - Nat
Succ (Pred Zero)Zero
Tamás Kozsik: Subtype Marks 54
Canonic :: Integer -> Integer{Can!}Canonic x =
let pair = CollectSuccPred x Zero Zero in Simplify (Fst pair) (Snd pair)
CollectSuccPred Zero pos neg = Pair pos negCollectSuccPred (Succ x) pos neg =
CollectSuccPred x (Succ pos) negCollectSuccPred (Pred x) pos neg =
CollectSuccPred x pos (Pred neg)Simplify Zero neg = negSimplify (Succ x) neg = TryToSimplify neg xTryToSimplify Zero pos = Succ posTryToSimplify (Pred x) pos = Simplify pos x
Tamás Kozsik: Subtype Marks 55
Factorial x = FactorialC (Canonic x)FactorialC Zero = Succ ZeroFactorialC (Succ x) = Multiply (Succ x)
(FactorialC x)
Abs x = AbsC (Canonic x)AbsC (Pred x) = Succ (AbsC x)AbsC x = x
Less x y = IsNegative (Compare x y)IsNegative :: Integer{Can} -> BooleanIsNegative (Pred x) = TrueIsNegative x = FalseCompare :: Integer -> Integer -> Integer{Can}Compare x y = Canonic (Substract x y)
Tamás Kozsik: Subtype Marks 56
Factorial
Factorial :: Integer{Nat} -> Integer{Can,Nat}Factorial x = FactorialC (Canonic x)
FactorialC :: Integer{Can,Nat} -> Integer{Can,Nat}
FactorialC Zero = Succ ZeroFactorialC (Succ x) = Multiply (Succ x)
(FactorialC x)
Tamás Kozsik: Subtype Marks 57
Zero, Succ and Pred
:: Integer = Zero | Succ Integer | Pred IntegerZero :>: Integer{Can,Nat}Zero :<: Integer{Can,Nat}Pred :>: Integer -> Integer Pred :<: Integer{c:Can,n:Nat} -> Integer{c:Can,n:Nat}Succ :>: Integer{c:Can,n:Nat} -> Integer{x:Can,n:Nat} | (x,c) (x,n)Succ :<: Integer{c:Can,c:Nat} -> Integer{c:Can,n:Nat}
Tamás Kozsik: Subtype Marks 58
Decomposition type of Pred
Pred :<: Integer{c:Can,n:Nat} -> Integer{c:Can,n:Nat}
Pred :<: Integer -> IntegerPred :<: Integer{Nat} -> Integer{Nat}Pred :<: Integer{Can} -> Integer{Can}Pred :<: Integer{Can,Nat} -> Integer{Can,Nat}
Impossible!
Tamás Kozsik: Subtype Marks 59
Decomposition type of Succ
Succ :<: Integer{c:Can,c:Nat} -> Integer{c:Can,n:Nat}
Succ :<: Integer -> IntegerSucc :<: Integer -> Integer{Nat}Succ :<: Integer{Can,Nat} -> Integer{Can}Succ :<: Integer{Can,Nat} -> Integer{Can,Nat}
Danger:Succ (Pred Zero)
Tamás Kozsik: Subtype Marks 60
Composition type of Succ
Succ :>: Integer{c:Can,n:Nat}
-> Integer{x:Can,n:Nat} | (x,c) (x,n)
Succ :>: Integer
-> Integer
Succ :>: Integer{Nat}
-> Integer{Nat}
Succ :>: Integer{Can,Nat}
-> Integer{Can,Nat}
Tamás Kozsik: Subtype Marks 61
Inequalities
• Constraints on subtype mark variables• Higher expressiveness• (x,y)
x requires yx can only be “true” if y is “true”, as well
• General technique to handle subtyping• Uniqueness• Hume
Tamás Kozsik: Subtype Marks 62
Add and Multiply
Add :: Integer{c:Can,n:Nat}
-> Integer{c:Can,n:Nat}
-> Integer{x:Can!,n:Nat!} | (x,c) (x,n)
Add Zero y = y
Add (Succ x) y = Add x (Succ y)
Add (Pred x) y = Add x (Pred y)
• Multiply has the same type
Tamás Kozsik: Subtype Marks 63
Factorial revisited
Factorial :: Integer{Nat} -> Integer{Can,Nat}Factorial x = FactorialC (Canonic x)
FactorialC :: Integer{Can,Nat} -> Integer{Can,Nat}
FactorialC Zero = Succ ZeroFactorialC (Succ x) = Multiply (Succ x)
(FactorialC x)
Follows from the type of Multiply
Tamás Kozsik: Subtype Marks 64
Programming languages issues
• Interference with other concepts• Type checking and type inference• Logical connectives versus inequalities• Specialization based on subtype marks
Tamás Kozsik: Subtype Marks 65
Logical connectives
• Would be natural to use (or, and, not…)• Higher complexity? (NP-hard?)• Expressiveness?
mulC :: Complex{p:Polar,c:Cart} -> Complex{p:Polar,c:Cart} -> Complex{p:Polar,c:Cart}mulC :: Complex{p1:Polar,c:Cart} -> Complex{p2:Polar,c:Cart} -> Complex{p1|p2:Polar,c:Cart!}
Tamás Kozsik: Subtype Marks 66
Specialization based on subtype marks
FactorialC :: Integer{Can,Nat}
-> Integer{Can,Nat}
Factorial :: Integer{Nat}
-> Integer{Can,Nat}
Factorial x = FactorialC (Canonic x)
Factorial :: Integer{Can,Nat}
-> Integer{Can,Nat}
Factorial x = FactorialC x
Tamás Kozsik: Subtype Marks 67
Software engineering issues
• Prototype compiler?• Building into a real language• IDE support
– Aspect-oriented approach– Interactive compiler
• Theorem prover versus runtime checks
Tamás Kozsik: Subtype Marks 68
Dynamics and CPPCC
• Dynamics:– Mobile code carrying its own type– Type checked (pattern matched) at consumer
• Certified-Proven-Properties-Carrying Code:– Mobile code carrying its specification
(Property + Certificate about proof)– Property matched against requirements at
consumer
• Subtype marks: in between
Tamás Kozsik: Subtype Marks 69
Conclusions
• Simple and natural extention to type systems• Connection to theorem provers• Partial correctness of programs• Library of functions with proven properties• Several similar approaches
– Some are for specific properties– Some are more expressive, but more complex
• Still many open questions
Tamás Kozsik: Subtype Marks 70
Homework
:: Complex = Cart Real Real
| Polar Real Real
| Both Real Real Real Real
Both :>: Real -> Real -> Real -> Real
-> Complex{Cart,Polar}
Tamás Kozsik: Subtype Marks 71
Abs
Abs :: Integer -> Integer{Can,Nat}
Abs x = AbsC (Canonic x)
AbsC :: Integer{Can} -> Integer{Can,Nat!}
AbsC (Pred x) = Succ (AbsC x)
AbsC x = x