+ All Categories
Home > Documents > Nested Refinements: A Logic for Duck Typing

Nested Refinements: A Logic for Duck Typing

Date post: 12-Feb-2016
Category:
Upload: dustin
View: 25 times
Download: 0 times
Share this document with a friend
Description:
Nested Refinements: A Logic for Duck Typing. Ravi Chugh , Pat Rondon, Ranjit Jhala (UCSD). What are “Dynamic Languages”?. d._onto = function ( arr,obj,fn ) { if ( !fn ) { arr.push ( obj ) ; } else if ( fn ) { var func = ( typeof fn == “ string ” ) ? obj [ fn ] : fn; - PowerPoint PPT Presentation
44
Nested Refinements: A Logic for Duck Typing Ravi Chugh , Pat Rondon, Ranjit Jhala (UCSD)
Transcript
Page 1: Nested Refinements: A Logic for Duck Typing

Nested Refinements:A Logic for Duck Typing

Ravi Chugh, Pat Rondon, Ranjit Jhala (UCSD)

Page 2: Nested Refinements: A Logic for Duck Typing

2

What are “Dynamic Languages”?d._onto = function(arr,obj,fn) { if (!fn) { arr.push(obj); } else if (fn) { var func = (typeof fn == “string”) ? obj[fn] : fn; arr.push(function() { func.call(obj); }); }}

mutation

tag-tests affect control flow

dictionary objects indexed by arbitrary string keys

first-class functions can appear inside objects

inheritance affects object lookup

Page 3: Nested Refinements: A Logic for Duck Typing

3

What are “Dynamic Languages”?

Lack of static types … makes rapid prototyping / multi-language applications easy

… makes reliability / performance / maintenance hard

Goal: Design a type system for these features

tag-tests

mutation

inheritance

first-class functions

dictionary objects

affect control flow

indexed by arbitrary string keys

can appear inside objects

affects object lookup

These alone are hard!

Page 4: Nested Refinements: A Logic for Duck Typing

4

tag-tests

first-class functions

dictionary objects

affect control flow

indexed by arbitrary string keys

can appear inside objects

if tagof f = “Str”then d.n + d[f](0) else d.n + f(0)

These alone are hard!

Page 5: Nested Refinements: A Logic for Duck Typing

5

Approach: Refinement Types

if tagof x = “Int” then 0 - x else not x

tag-tests

Type environment tracks control flow predicates

{|tag()=“Int”tag()=“Bool”}x ::

{|tag()=“Bool”}x ::

{|tag()=“Int”}x ::

Page 6: Nested Refinements: A Logic for Duck Typing

6

Approach: Refinement Types

d.n + d[m]

d,k,k’,x. kk’ sel(upd(d,k,x),k) = x

sel(upd(d,k,x),k’) = sel(d,k’)sel(empty,k) = bot

McCarthy axioms

{|tag()=“Dict”tag(sel(,“n”))=“Int”tag(sel(,m))=“Int”}

d ::

dictionaries

tag-tests

Page 7: Nested Refinements: A Logic for Duck Typing

7

Approach: Refinement Types

1 + f (0)first-class functions

dictionaries

tag-tests

Clear separation of base and arrow typesT ::= {|p} | x:T1T2

x:{|tag()=“Int”}{|tag()=“Int”}f ::

x:{|tag()=“Int”}{|=x}x.x ::

Page 8: Nested Refinements: A Logic for Duck Typing

8

Approach: Refinement Types

1 + f (0)first-class functions

dictionaries

tag-tests

Page 9: Nested Refinements: A Logic for Duck Typing

9

Approach: Refinement Types

1 + d[f](0)

{|tag()=“Dict”

sel(,f) ??? }d ::

first-class functions

dictionaries

tag-tests

Key Challenges

1. How to describe arrow inside formula?

2. How to keep type checking decidable?

Page 10: Nested Refinements: A Logic for Duck Typing

10

• Reuse refinement type architecture

• Find a decidable refinement logic for– Tag-tests– Dictionaries– Lambdas

• Define nested refinement type architecture

Approach: Refinement Types

✓✗✓✓*

Page 11: Nested Refinements: A Logic for Duck Typing

11

Nested Refinements

{|tag()=“Dict” sel(,f):: }

d ::

{|tag()=“Int”}

{|tag()=“Int”}

uninterpreted predicate“x::U” says“x has-type U”

uninterpreted constantin the logic…

… but syntactic arrowin the type system!

1 + d[f](0)

Page 12: Nested Refinements: A Logic for Duck Typing

12

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

Page 13: Nested Refinements: A Logic for Duck Typing

13

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

Page 14: Nested Refinements: A Logic for Duck Typing

14

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

Page 15: Nested Refinements: A Logic for Duck Typing

15

let foo f d = if tagof f = “Str” then d.n + d[f](0) else d.n + f(0)

T ::= {|p}U ::= x:T1T2

p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

f:{|Str()::IntInt}d:{|Dict() Int(.n) Str(f)[f]::IntInt}Int

foo ::

Page 16: Nested Refinements: A Logic for Duck Typing

16

let foo f d = if tagof f = “Str” then d.n + d[f](0) else d.n + f(0)

T ::= {|p}U ::= x:T1T2

p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

f:{|Str()::IntInt}d:{|Dict() Int(.n) Str(f)[f]::IntInt}Int

foo ::

Page 17: Nested Refinements: A Logic for Duck Typing

17

let foo f d = if tagof f = “Str” then d.n + d[f](0) else d.n + f(0)

T ::= {|p}U ::= x:T1T2

p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

f:{|Str()::IntInt}d:{|Dict() Int(.n) Str(f)[f]::IntInt}Int

foo ::

tag()=“Str”

{|tag()=“Int”}

{|tag()=“Int”}

Page 18: Nested Refinements: A Logic for Duck Typing

18

let foo f d = if tagof f = “Str” then d.n + d[f](0) else d.n + f(0)

T ::= {|p}U ::= x:T1T2

p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

f:{|Str()::IntInt}d:{|Dict() Int(.n) Str(f)[f]::IntInt}Int

foo ::

Page 19: Nested Refinements: A Logic for Duck Typing

19

let foo f d = if tagof f = “Str” then d.n + d[f](0) else d.n + f(0)

T ::= {|p}U ::= x:T1T2

p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

f:{|Str()::IntInt}d:{|Dict() Int(.n) Str(f)[f]::IntInt}Int

foo ::

sel(,“n”) sel(,f)

Page 20: Nested Refinements: A Logic for Duck Typing

20

let foo f d = if tagof f = “Str” then d.n + d[f](0) else d.n + f(0)

T ::= {|p}U ::= x:T1T2

p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

f:{|Str()::IntInt}d:{|Dict() Int(.n) Str(f)[f]::IntInt}Int

foo ::

Page 21: Nested Refinements: A Logic for Duck Typing

21

{|::

}

{|::

} Int

d: {|tag()=“Dict” tag(sel(,“n”))=“Int” tag(f)=“Str” sel(,f):: }IntInt

f: {|tag()=“Str”:: }IntInt

let foo f d = if tagof f = “Str” then d.n + d[f](0) else d.n + f(0)

T ::= {|p}U ::= x:T1T2

p ::= pq | … | x = y | x < y | … | tag(x) = “Int” | … | sel(x,y) = z | … | x::U

foo ::

Page 22: Nested Refinements: A Logic for Duck Typing

22

Nested Refinements

• Type Language

• Subtyping

• Extensions

• Recap

Page 23: Nested Refinements: A Logic for Duck Typing

23

Subtyping

T ::= {|p} | x:T1T2

traditional refinements

Implication

SMT Solver

Subtyping

{|true}Top

tag()=“Int” true

{|tag()=“Int”}Int

Int <: Top

Page 24: Nested Refinements: A Logic for Duck Typing

24

Subtyping

T ::= {|p} | x:T1T2

traditional refinements

Implication

SMT Solver

Subtyping

{|true}Top

{|tag()=“Int”}Int

Top Int <: Int Int

Int <: Top Int <: Int

tag()=“Int” true

tag()=“Int” tag()=“Int”

Page 25: Nested Refinements: A Logic for Duck Typing

25

Subtyping

T ::= {|p} | x:T1T2

traditional refinements

Implication

SMT Solver

Subtyping

{|true}Top

{|tag()=“Int”}Int

Top Int <: Int Int

Int <: Top Int <: Int

tag()=“Int” true

tag()=“Int” tag()=“Int”

Arrow Rule

Page 26: Nested Refinements: A Logic for Duck Typing

26

Subtyping

T ::= {|p} | x:T1T2

traditional refinements

Implication

SMT Solver

Subtyping Arrow Rule

Decidable if:• Only values in formulas• Underlying theories decidable

With nested refinements:• No new theories• But implication is imprecise!

Page 27: Nested Refinements: A Logic for Duck Typing

27

Subtyping with Nesting

Implication

SMT Solver

Subtyping

Invalid, as these are distinctuninterpreted constants

::TopInt ::IntInt✗

Page 28: Nested Refinements: A Logic for Duck Typing

28

Subtyping with Nesting

Implication

SMT Solver

Subtyping Arrow Rule

When goal is base predicate:p q

When goal is “has-type” predicate:p x::U

Implication

SMT Solver

Subtyping

p x::U’

U’<:U

p q

Page 29: Nested Refinements: A Logic for Duck Typing

29

p ::TopInt

UninterpretedReasoning

Subtyping with Nesting

p ::Int Int

Normalize formulas tosubdivide obligations appropriately

TopInt <: IntInt

+ SyntacticReasoning

Page 30: Nested Refinements: A Logic for Duck Typing

30

Nested Refinements

• Type Language

• Subtyping

• Extensions

• Recap

Page 31: Nested Refinements: A Logic for Duck Typing

31

Extensions• Simple to add additional type constructors

• Extend the grammar of type terms

• Add additional syntactic subtyping rules

Arrow Rule

Covariant List Rule

Null List Rule

SyntacticRules

U ::= x:T1T2 | A | List[T] | Null

Page 32: Nested Refinements: A Logic for Duck Typing

32

Map

let map f xs = if xs = null then null else f xs[“hd”] :: map f xs[“tl”]

∀A,B. {|::AB}{|::List[A]}{|::List[B]}

encode recursive data as dictionaries

Page 33: Nested Refinements: A Logic for Duck Typing

33

Filterlet filter f xs = if xs = null then null else if f xs[“hd”] then xs[“hd”] :: filter f xs[“tl”] else filter f xs[“tl”]

∀A,B.{|::x:A{|=Truex::B}} {|::List[A]} {|::List[B]}

usual definition, but an interesting type

Page 34: Nested Refinements: A Logic for Duck Typing

34

Dispatch

let dispatch d f = d[f] d

∀A,B.d:{|Dict()::A} {|Str()d[]::AB} {|::B}

a form of “bounded quantification” sinced::A but additional constraints on A

Page 35: Nested Refinements: A Logic for Duck Typing

35

Recap• Refinement types are a compelling approach

– Dynamic dictionaries require dependency

– Tag-tests require path sensitivity

• But, not enough for lambdas in dictionaries

• Nested refinement types are a clean solution– Natural way to describe dynamic idioms

– Novel subtyping remains decidable and automatic

• Interesting soundness proof

Page 36: Nested Refinements: A Logic for Duck Typing

36

Future Work• Extend to imperative JavaScript setting

– Employ strong update techniques– Track prototype chain for inheritance

• Better inference– Untyped programmers allergic to annotations – Perhaps utilize run-time information

• Applications– JavaScript benchmarks (e.g. SunSpider)– JavaScript frameworks (e.g. Dojo)

Page 37: Nested Refinements: A Logic for Duck Typing

37

Thanks!

Dhttp://cseweb.ucsd.edu/~rchugh/research/nested/

::

Page 38: Nested Refinements: A Logic for Duck Typing

38

Extra Slides

Page 39: Nested Refinements: A Logic for Duck Typing

39

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)}

Page 40: Nested Refinements: A Logic for Duck Typing

40

• 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)

Page 41: Nested Refinements: A Logic for Duck Typing

41

Functional 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:{|Str()::ATop}obj:{|::A (f=null::AInt) (Str(f)[f]::AInt)}List[TopTop]

onto ::

Page 42: Nested Refinements: A Logic for Duck Typing

42

Functional 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|Str(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 ::

Page 43: Nested Refinements: A Logic for Duck Typing

43

Normalization• TODO

Page 44: Nested Refinements: A Logic for Duck Typing

44

Related Work• TODO


Recommended