This document describes dynamic type inference (DTI) for gradually typed languages with Hindley-Milner type inference. DTI infers types for type variables left undecided by compile-time type inference by instantiating type variables during evaluation based on the types of values. The approach is formalized in a blame calculus λBDTI that extends a simply typed lambda calculus with type variables, casts for runtime type checking, and a reduction relation for DTI. Properties like soundness and completeness of DTI and the gradual guarantee are proven for λBDTI.
Engaging Eid Ul Fitr Presentation for Kindergartners.pptx
Dynamic Type Inference for Gradual Hindley–Milner Typing
1. Dynamic Type Inference
for Gradual Hindley–Milner Typing
!1
Yusuke Miyazaki
Kyoto University
Japan
Taro Sekiyama
National Institute of Informatics
Japan
Atsushi Igarashi
Kyoto University
Japan
POPL 2019 / Cascais, Portugal
2. Gradual Typing
[Siek & Taha ’06]
Framework to integrate static and dynamic typing in a single
language
• Introduces the dynamic type to specify dynamically typed
parts in a program
• Combines typechecking at compile-time and run-time
• Enables gradual code evolution from a dynamically typed
program to a statically typed program
!2
3. Gradual Typing: Example
!3
# let g_avg (x: int) (y: *) = (x + y) / 2
val g_avg: int → * → int
# g_avg 3 5
4
# g_avg "hello" 5
Compile-time type error:
parameter “x” expects
int value
# g_avg 3 "hello"
Run-time error:
operator (+) expects int value
Value of any type can be passed
to a parameter with the dynamic type
Whether y has int type or not is
checked at run-timeThe dynamic type
Whether x has int type or not is
checked at compile-time
4. Gradual Typing: Another Example
!4
# (λf:*. f 3) (λx:int. x)
3: int *
# (λf:*. f 3) (λx:str. x)
Run-time error:
The parameter “x” expects a string value.
But an integer value 3 is passed to the parameter.
λx:int.x is passed to f:* 3 is passed to x:int
Type annotation can affect the result of evaluation
3 is passed to x:str
Value tagged with int
5. Our Work
Proposes the blame calculus λB
DTI to give a new semantics of the
gradually typed language with type inference and Hindley–Milner
polymorphism
• Introduces dynamic type inference (DTI) to deal with type variables
left undecided by compile-time type inference
• Proves properties of the calculus
• Soundness and completeness of dynamic type inference
• Gradual guarantee of λB
DTI and ITGL
• Implements an interpreter ymyzk/lambda-dti
!5
6. Outline
• Introduction
• Problem: Undecided Type Variables in ITGL
• Background: Implicitly Typed Gradual Language (ITGL)
• Problem of Type Variables Undecided by Compile-Time Type Inference
• Dynamic Type Inference
• Properties
• Conclusion
!6
7. Implicitly Typed Gradual Language (ITGL)
[Garcia & Cimini POPL ’15]
• Gradually typed language with let-polymorphism
• Compile-time type inference algorithm that infers static types
for where type annotations are omitted
• Static types: types do not contain the dynamic type
• Principal type property
!7
8. Compile-Time Type Inference of ITGL
!8
In: (λf. f 3) (λx. x)
Out: (λf:int→int. f 3) (λx:int. x)
Result: 3
In: (λf:*. f 3) (λx. x)
Out: (λf:*. f 3) (λx:α. x)
Add *
9. Problem of ITGL
!9
In: (λf. f 3) (λx. x)
Out: (λf:int→int. f 3) (λx:int. x)
Result: 3
In: (λf:*. f 3) (λx. x)
Out: (λf:*. f 3) (λx:α. x)
Result1: 3: int * (if α is replaced with int before evaluation)
Result2: Run-time error (otherwise)
Left undecided by type inference,
but cannot be ignored at run-time
Add *
bool int str
int→int int→bool
int→str bool→int …
Generally, it is difficult to find a static type for α at compile-time !
Candidates for α
10. Our Solution
!10
Find static types for undecided type variables during evaluation
(λf:*. f 3) (λx:α. x)
Run-time system will find out α to be int
11. Another Idea: Replacing with the Dynamic Type
!11
Replacing undecided type variables with the dynamic type may
sounds like a good idea, but we find some problems:
• Goes against with the original idea of ITGL that a type variable
is a placeholder for a static type
• Makes it difficult to detect a type error earlier
• Because it can make evaluation successful even when there
is no static substitutions that makes evaluation successful
We decided not to use this approach "
12. Outline
• Introduction
• Problem: Undecided Type Variables in ITGL
• Dynamic Type Inference
• Background: Cast for Run-Time Typecheck
• Dynamic Type Inference
• Properties
• Conclusion
!12
13. Cast for Run-Time Typecheck
[Wadler & Fiedler ESOP ’09]
A term for performing run-time typecheck in blame calculi
e: U U’
• Cast failure is expressed as a special term blame
• The paper deals with blame labels formally
• Casts are inserted where run-time checks are required during
translation from a gradually typed language to a blame
calculus
!13
Cast of a term e from type U to U’
14. Examples: Run-Time Typecheck with Casts
!14
(λx:*. x + 2) 3
⇝ (λx:*. (x: * int) + 2) (3: int *)
⟼ (3: int * int) + 2
⟼ 3 + 2 ⟼ 5
(λx:*. x + 2) "hello"
⇝ (λx:*. (x: * int) + 2) ("hello": str *)
⟼ ("hello": str * int) + 2
⟼ blame + 2 ⟼ blame
Run-time typecheck:
cast from int to int succeeds
Run-time typecheck:
cast from str to int fails
Value tagged with int
Cast inserting
translation
15. Another Example: Run-Time Typecheck with Casts
!15
(λf:*. f 3) (λx:int. x)
⇝ (λf:*. (f: * *→*) (3: int *))
((λx:int. x): int→int *)
⟼+((λx:int. x) (3: int * int)): int *
⟼ ((λx:int. x) 3): int *
⟼+ 3: int *
Run-time typecheck:
cast from int to int succeeds
16. Dynamic Type Inference
!16
(λf:*. f 3) (λx:α. x)
⇝ (λf:*. (f: * *→*) (3: int *))
((λx:α. x): α→α *)
⟼+((λx:α. x) (3: int * α)): α *
⟼ ((λx:int. x) 3): int *
⟼+ 3: int *
α is instantiated with int
DTI: Instantiates α with the type attached to
the value (int) and proceeds the evaluation
Generated substitution:
[α↦int]
Resulted in a value thanks to DTI
Left undecided by compile-time inference
17. Simply typed blame calculus + type variables
(+ let-polymorphism discussed in the paper)
U ::= * (Dynamic Type)
| α (Type Variable)
| int (Base Type)
| U→U (Function Type)
Formalizing DTI: λB
DTI
!17
e ::= x (Variable)
| c (Constant)
| λx:U.e (Abstraction)
| e1 e2 (Application)
| e: U1 U2 (Cast)
| blame (Blame)
18. Formalizing DTI: Reduction Relation
Two reduction rules for dynamic type inference
!18
v: *→* * α ⟶ v: *→* * α1→α2
[α↦α1→α2]
Type substitution obtained by DTI:
Instantiate α with int then proceed reduction
v: int * α ⟶ v
[α↦int]
e ⟶ e’S
Generate fresh type
variables α1 and α2
19. Formalizing DTI: Evaluation Relation
The evaluation rule makes sure that a type variable is
instantiated at most once
Example:
!19
e ⟶ e’
E[e] ⟼ S(E[e’])S
Apply the type substitution S to the entire term
S
Evaluation context
Reduction of a subterm
3: int * α ⟶ 3
(λx:α. x) (3: int * α) ⟼ (λx:int. x) 3
[α↦int]
[α↦int]
e ⟼ e’S
21. Properties
Prove the following properties of the calculus
• Type safety of λB
DTI
• Soundness and completeness of DTI
• Translation from ITGL to λB
DTI is type-preserving
• Gradual guarantee of λB
DTI and ITGL
!21
22. Soundness and Completeness of DTI
DTI always returns an “appropriate” type substitution if it exists
• Soundness of DTI:
• A type substitution yielded by DTI is appropriate
• Completeness of DTI:
• If an appropriate type substitution exists, DTI returns one
!22
By applying it before evaluation,
the program terminates at a value
23. Soundness of Dynamic Type Inference
1. If a program e results in a value or blame r with DTI, then
applying the substitution S obtained by DTI beforehand does
not change the result
2. If a program e evaluates to blame with DTI, applying any
substitution results in blame
!23
Theorem (Soundness): Suppose ⊢ e: U
1. If e ⟼* r then, for any S’ s.t. ftv(S’(S(e))) = ∅, S’(S(e)) ⟼* S’(r)
for some S’’
2. If e ⟼* blame then, for any S’, S’(e) ⟼* blame for some S’’
S
S
S’’
S’’
24. Completeness of Dynamic Type Inference
1. If there is a type substitution S that makes a program result in
a value v, then evaluation with DTI also results in a related
value v’
2. If there is a type substitution that makes a program diverge,
evaluation with DTI also diverges
!24
Theorem (Completeness): Suppose ⊢ e: U
1. If S(e) ⟼* v, then e ⟼* v’ and S’’(v’) = v for some v’, S’, S’’
2. If S(e) diverges, then e diverges
∅ S’
25. In the Paper and Artifact…
• Full definition of the calculus λB
DTI
• Syntax, type system, operational semantics, translation from ITGL
• Extension to let-polymorphism which is non-parametric [Ahmed et al. POPL ’11]
• let x = v in e behaves the same as e[x:=v]
• Properties of the calculus
• Type safety
• Soundness and completeness of DTI
• Gradual guarantee of λB
DTI and ITGL with non-trivial precision relation
• Implementation of the calculus
!25
26. Related Work
• Replacing undecided type variables with the dynamic type
[Henglein & Rehof FPCA ’95 / Xie et al. ESOP ’18]
• Their work:
• Provides more permissive semantics
• Our work:
• Enables earlier bug detection
• Consistent with the idea that a type variable in ITGL is a
placeholder for a static type
!26
27. Conclusion
Blame calculus with dynamic type inference and let-polymorphism
• Dynamic type inference
• Instantiates undecided type variables along with evaluation
• Let-Polymorphism
• Properties
• Soundness and completeness of DTI
• Gradual guarantee of λB
DTI and ITGL
!27