Android UX Tricks: Nested Scrolling without Nested Scrolling
Nested Refinements: A Logic for Duck Typing
description
Transcript of Nested Refinements: A Logic for Duck Typing
Nested Refinements:A Logic for Duck
Typing
Ravi Chugh, Pat Rondon, Ranjit Jhala (UCSD)
::
2
What are “Dynamic Languages”?
let onto callbacks f obj = if f = null then new List(obj, callbacks) else let cb = if tagof f = “Str” then obj[f] else f in new List(fun () -> cb obj, callbacks)
tag tests affect control flow
dictionary objects indexed by arbitrary string keys
first-class functions can appear inside objects
3
Problem: Lack of static types… makes rapid prototyping / multi-language applications easy
… makes reliability / performance / maintenance hard
This Talk: System D… a type system for these features
tag tests affect control flow
dictionary objects indexed by arbitrary string keys
first-class functions can appear inside objects
…
occurrence types
∨, ∧
Our Approach: Quantifier-free formulas
tag tests affect control flow
dictionary objects indexed by arbitrary string keys
first-class functions can appear inside objects
Expressiveness
Usability
F≤
Coq
refinement types
nested refinements
syntactic approaches dependent approaches
1. increase expressiveness
2. retain level of automation
5
Functions inside dictionariesChallenge:
{|tag()=“Int”tag()=“Bool”}x ::
{|tag()=“Dict”tag(sel(,“n”))=“Int”tag(sel(,m))=“Int”}
d ::
tag tests affect control flow
dictionary objects indexed by arbitrary string keys
first-class functions can appear inside objects
6
Key Idea: Nested Refinements
{|tag()=“Dict” sel(,f):: }
d ::
{|tag()=“Int”}
{|tag()=“Int”}
uninterpreted predicate“x::U” says“x has-type U”
syntactic arrow type…
1 + d[f](0)
7
Key Idea: Nested Refinements
{|tag()=“Dict” sel(,f):: }
d ::
{|tag()=“Int”}
{|tag()=“Int”}
uninterpreted predicate“x::U” says“x has-type U”
1 + d[f](0)
syntactic arrow type…
… but uninterpreted constant in the logic
8
• All values described by refinement formulasT ::= {|p}
• “Has-type” predicate for arrows in formulasp ::= … | x :: y:T1T2
• Can express idioms of dynamic languages
• Automatic type checking– Decidable refinement logic
– Subtyping = SMT Validity + Syntactic Subtyping
Key Idea: Nested Refinements
Outline
Intro
Examples
Subtyping
Type Soundness
Conclusion9
10
let negate x = if tagof x = “Int” then 0 – x else not x
y:Top{|=tag(y)}tagof ::
x:{|tag()=“Int”tag()=“Bool”} {|tag()=tag(x)}
x:IntOrBool{|tag()=tag(x)}
y:{|true}
11
IntOrBoolx ::Γ
{|Int()}x ::{|Int()}0 - x ::
x:IntOrBool{|tag()=tag(x)}
let negate x = if tagof x = “Int” then 0 – x else not x
tag(x)=“Int”
type environment
✓
✓SMT Solver
✓
12
IntOrBoolx ::Γ
{|Bool()}x ::{|Bool()}not x ::
x:IntOrBool{|tag()=tag(x)}
let negate x = if tagof x = “Int” then 0 – x else not x
not(tag(x)=“Int”)
type environment
SMT Solver
✓✓
✓
13
{|:: }x: IntOrBool {|tag()=tag(x)}
x:IntOrBool{|tag()=tag(x)}
Nesting structure hidden with syntactic sugar
14
Dictionary Operations
d:Dictk:Str{|=true has(d,k)}mem ::
d:Dictk:{|has(d,)}{|=sel(d,k)}get ::
d:Dictk:Strx:Top{|=upd(d,k,x)}set ::
Types in terms of McCarthy operators
15
let getCount d c = if mem d c then toInt (d[c]) else 0
d:Dictc:StrInt
{|=true has(d,c)}
safe dictionary key lookup
get d c
16
let incCount d c = let i = getCount d c in {d with c = i + 1}
d:Dictc:StrInt
d:Dictc:Str{|EqMod(,d,c)Int([c])}
tag(sel(,c))=“Int”
let getCount d c = if mem d c then toInt (d[c]) else 0
set d c (i+1)
17
T ::= {|p}
p ::= … | x::U
U ::= y:T1T2
| A
| List T
| Null
Adding Type Constructors
“type terms”
18
let apply f x = f x
∀A,B.{|::{|::A}{|::B}} {|::A} {|::B}
∀A,B.(AB)AB
19
let dispatch d f = d[f](d)
∀A,B.d:{|::A}f:{|d[]::AB}{|::B}
d::A but additional constraints on A≈ ∀A<:{f:AB}.d::A
a form of“bounded quantification”
20
let map f xs = if xs = null then null else new List(f xs[“hd”], map f xs[“tl”])
∀A,B. {|::AB}{|::List[A]}{|::List[B]}
encode recursive data as dictionaries
∀A,B.(AB)List[A]List[B]
21
let filter f xs = if xs = null then null else if not (f xs[“hd”]) then filter f xs[“tl”] else new List(xs[“hd”], filter f xs[“tl”])
∀A,B.(x:A{|=truex::B}List[A]List[B]
usual definition,but an interesting type
Outline
Intro
Examples
Subtyping
Type Soundness
Conclusion22
23
SMT Γ=42 tag()=“Int”
Γ {|=42} < Int_|
(Int,IntInt)IntapplyInt ::
applyInt (42,negate)
x:IntOrBool{|tag()=tag(x)}negate ::
Γ
✓
type environment
24
SMT
…negate::x:IorB{|tag()=tag(x)}…=negate
::IntInt
Γ {|=negate} < {|::IntInt}_|
(Int,IntInt)IntapplyInt ::
applyInt (42,negate)
x:IntOrBool{|tag()=tag(x)}negate ::
Γtype environment
25
Γ {|=negate} < {|::IntInt}_|
(Int,IntInt)IntapplyInt ::
applyInt (42,negate)
x:IntOrBool{|tag()=tag(x)}negate ::
Γ
✗ distinct uninterpreted
constants!
type environment
SMT
…negate::x:IorB{|tag()=tag(x)}…=negate
::IntInt
26
IorB {|tag()=tag(x)} <: Int Int
Int <: IorB {|tag()=tag(x)} <: Int
tag()=“Int” tag()=“Int” tag()=“Bool”
tag()=“Int”tag()=tag(x) tag()=“Int”
Invalid, since these are uninterpreted constants
Want conventional syntactic subtyping
✓ ✓
::x:IorB{|tag()=tag(x)}
::IntInt✗
27
Subtyping with Nesting
base predicate: p qij
1) Convert q to CNF clauses (q11…)…(qn1…)2) For each clause, discharge some literal qij as follows:
To prove p q :
anything except x::Ue.g. tag()=tag(x)e.g. tag(sel(d,k))=“Int”
28
Subtyping with Nesting
Implication
SMT Solver
Subtyping Arrow Rule
base predicate: p qij “has-type” predicate: p x::U
Implication
SMT Solver
Subtyping
p x::U’
U’ <: U
p qij
1) Convert q to CNF clauses (q11…)…(qn1…)2) For each clause, discharge some literal qij as follows:
To prove p q :
29
UninterpretedReasoning
…negate::x:IorB{|tag()=tag(x)}…=negate
::x:IorB{|tag()=tag(x)}
applyInt (42,negate)
Γ {|=negate} < {|::IntInt}_|
+
SyntacticReasoning
Γ x:IorB{|tag()=tag(x)} <: IntInt_|
Outline
Intro
Examples
Subtyping
Type Soundness
Conclusion30
31
0 :: {|x.x+1::IntInt}_|
x.x+1 :: {|::IntInt}_|
f:{|::IntInt} 0 :: {|f::IntInt}_|
SubstitutionLemma
_| v :: TxandIf x:Tx,Γ e[:: T_|
Γ[v/x] e[v/x] :: T[v/x]_|then
independent of 0, and just echoes the binding from the environment
32
0 :: {|x.x+1::IntInt}_|
SMT =0 x.x+1::IntInt✗{|=0} < {|x.x+1::IntInt}0 :: {|
=0}
SubstitutionLemma
_| v :: TxandIf x:Tx,Γ e[:: T_|
Γ[v/x] e[v/x] :: T[v/x]_|then
1st attempt
33
0 :: {|x.x+1::IntInt}_|
{|=0} < {|x.x+1::IntInt}0 :: {|=0}
SubstitutionLemma
_| v :: TxandIf x:Tx,Γ e[:: T_|
Γ[v/x] e[v/x] :: T[v/x]_|then✗SMT =0 ::U’
Arrow U’ <: IntInt
+2nd attempt✗
34
x.x+1::IntInt|=I
x.x+1::{|::IntInt}|_
SMT Γ p qΓ {|=p} < {|=q}_|
[S-Valid-Uninterpreted]
|=I Γ p qΓ {|=p} < {|=q}_|
[S-Valid-Interpreted]
iff
• Rule not closed under substitution
• Interpret formulas by “hooking back” into type system
• Stratification to create ordering for induction
n
n-1
n
n
35
Type Soundness
StratifiedSubstitutionLemma
_| v :: TxandIf x:Tx,Γ e[:: T_|
Γ[v/x] e[v/x] :: T[v/x]_|then n+1
nn
StratifiedPreservation
e vandIf e[:: T_| 0_|then v[:: Tm for some m
“Level 0” for type checking source programs,using only [S-Valid-Uninterpreted]
artifact of the metatheory
36
Recap• Dynamic languages make heavy use of:
– run-time tag tests, dictionary objects, lambdas
• Nested refinements– generalizes refinement type architecture– enables combination of dictionaries and lambdas
• Decidable refinement logic– all proof obligations discharged algorithmically– novel subtyping decomposition to retain precision
• Syntactic type soundness
37
Future Work• Imperative Updates
• Inheritance (prototypes in JS, classes in Python)
• Applications
• More local type inference / syntactic sugar
• Dictionaries in statically-typed languages
38
Thanks!
Dravichugh.com/nested
::
39
Extra Slides
40
Constants
tagof :: x:Top{|=tag(x)}
mem :: d:Dictk:Str{|Bool()=True has(d,k)}get :: d:Dictk:{|Str()has(d,)}{|=sel(d,k)}
set :: d:Dictk:Strx:Top{|=upd(d,k,x)}
rem :: d:Dictk:Str{|=upd(d,k,bot)}
41
• Types
• Formulas
• Logical Values
Macros{|tag()=“Int”}Int
x:T1T2 {|:: }x:T1T2
tag(x) = “Str”Str(x)
sel(,“k”)x.k sel(,k)x[k]
sel(d,k)!=bothas(d,k) ∀k’. k’!=k sel(d,k)!=sel(d’,k)
EqMod(d,d’,k)
42
Ontolet onto callbacks f obj = if f = null then new List(obj,callbacks) else let cb = if tagof f = “Str” then obj[f] else f in new List(fun () -> cb obj, callbacks)
∀A. callbacks:List[TopTop]f:{|=nullStr()::ATop}obj:{|::A (f=null::AInt) (Str(f)[f]::AInt)}List[TopTop]
onto ::
functional version of Dojo function
43
Onto (2)let onto (callbacks,f,obj) = if f = null then new List(obj,callbacks) else let cb = if tagof f = “Str” then obj[f] else f in new List(fun () -> cb obj, callbacks)
callbacks:List[TopTop]*f:{g|g=nullStr(g)g::{x|x=obj}Top}*obj:{o|(f=nullo::{x|x=o}Int) (Str(f)o[f]::{x|x=o}Int)}List[TopTop]
onto ::
functional version of Dojo function
44
Traditional vs. Nested Refinements
45
• Reuse refinement type architecture
• Find a decidable refinement logic for– Tag-tests– Dictionaries– Lambdas
• Define nested refinement type architecture
Approach: Refinement Types
✓✗✓✓*
46
Nested Refinements
T ::= {|p}U ::= x:T1T2
p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x :: U
• Refinement formulas over a decidable logic– uninterpreted functions, McCarthy arrays, linear arithmetic
• Only base values refined by formulasAll values
T ::= {|p} | x:T1T2
p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | …
traditional refinements
47
Nested Refinements
T ::= {|p}U ::= x:T1T2
p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U
• Refinement formulas over a decidable logic– uninterpreted functions, McCarthy arrays, linear arithmetic
• Only base values refined by formulas• “has-type” allows “type terms” in formulas
All values
T ::= {|p} | x:T1T2
p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | …
traditional refinements
48
Nested Refinements
T ::= {|p}U ::= x:T1T2
p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U
• Refinement formulas over a decidable logic– uninterpreted functions, McCarthy arrays, linear arithmetic
• Only base values refined by formulas• “has-type” allows “type terms” in formulas
All values
49
Subtyping (Traditional Refinements)
T ::= {|p} | x:T1T2
traditional refinements
Implication
SMT Solver
Subtyping
tag()=“Int” trueInt <: Top
50
Subtyping (Traditional Refinements)
T ::= {|p} | x:T1T2
traditional refinements
Implication
SMT Solver
Subtyping
Top Int <: Int Int
Int <: Top Int <: Int
tag()=“Int” true
tag()=“Int” tag()=“Int”
51
Subtyping (Traditional Refinements)
T ::= {|p} | x:T1T2
traditional refinements
Implication
SMT Solver
Subtyping
Top Int <: Int Int
Int <: Top Int <: Int
tag()=“Int” true
tag()=“Int” tag()=“Int”
Arrow Rule
52
Subtyping (Traditional Refinements)
T ::= {|p} | x:T1T2
traditional refinements
Implication
SMT Solver
Subtyping Arrow Rule
Decidable if:• Only values in formulas• Underlying theories decidable