Simon PJ Feb 2012 - ETH Zlaser.inf.ethz.ch/2012/slides/PeytonJones/Deferring type errors.pdf ·...
Transcript of Simon PJ Feb 2012 - ETH Zlaser.inf.ethz.ch/2012/slides/PeytonJones/Deferring type errors.pdf ·...
-
Simon PJ
Feb 2012
-
The rise of dynamic languages
“The type errors are getting in my way”
Feedback to programmer Static: type system
Dynamic: run tests
“Programmer is denied dynamic feedback in the periods when the program is not globally type correct” [DuctileJ, ICSE’11]
-
Underlying problem: forces programmer to fix all type errors before running any code.
Goal: Damn the torpedos
Compile even type-incorrect programs to executable code, without losing type soundness
-
Not just the command line: can load modules with type errors --- and run them
bash$ ghci –fdefer-type-errors
ghci> let foo = (True, ‘a’ && False)
Warning: can’t match Char with Bool
gici> fst foo
True
ghci> snd foo
Error: can’t match Char with Bool
-
DuctileJ uses reflection
Our implementation has zero runtime cost
(But we are a little bit more eager about raising a runtime type error than they are.)
-
Just a hack? No! A thing of beauty?
Haskell program
System FC
Typecheck and desugar
-
3+(4::Int)
(+) d7 3 4 d7 : Num Int
Type checker
Constraints Elaborated program (mentioning constraint variables)
-
let d7:Num Int = dNumInt
(+) d7 3 4 d7 : Num Int
Constraints Elaborated program (mentioning constraint variables)
Solve
Constraint solver creates a value binding giving evidence for each constraint
-
\x. x && False
\(x:) (x c7) && False c7 : ~ Bool
Haskell term
Constraints Elaborated program (mentioning constraint variables)
-
let = Bool let c7: ~Bool = refl Bool
\(x:). (x c7) && False c7 : ~ Bool
Constraints Elaborated program (mentioning constraint variables)
Solve
Solver also solves for unknown types
Equality constraints have evidence
A cast (e1 c) converts a term from one type to another
-
(True, ‘a’ && False)
(True, (‘a’ c7) && False) c7 : Int ~ Bool
Haskell term
Constraints Elaborated program (mentioning constraint variables)
-
let c7: Int~Bool = error “Can’t match ...”
(True, (‘a’ c7) && False) c7 : Int ~ Bool
Constraints Elaborated program (mentioning constraint variables)
Solve
Use lazily evaluated evidence
Cast evaluates its evidence
Error triggered when (and only when) ‘a’ must have type Bool
-
let c7: Int~Bool = error “Can’t match ...”
in (True, (‘a’ c7) && False)
The intermediate language is System FC
Strongly typed like System F
So even these type-incorrect programs enjoy the type soundness property
GHC does carry all these coercions throughout; and checks them with –dcore-lint
-
But is this efficient?
How do you make it efficient enough?
ML typechecking has zero runtime cost; so anything involving these casts and coercions looks inefficient, doesn’t it?
EFFICIENCY?
-
Remember: cast evaluates its coercion argument
Think of (refl Bool) as a value, that does not need to be evaluated by cast
Moreover, the only thing you need about this value is to have it; once it is evaluated you don’t need anything else
Sounds rather ad-hoc
let c7: Bool~Bool = refl Bool in (x c7) && False)
-
Expose evaluation to optimiser
data Int = I# Int# plusInt :: Int -> Int -> Int plusInt x y = case x of I# a -> case y of I# b -> I# (a +# b)
x `plusInt` x = case x of I# a -> case x of I# b -> I# (a +# b) = case x of I# a -> I# (a +# a)
Library code Inline + optimise
-
So (~#) is the primitive type constructor
(#) is the primitive language construct
And (#) is erasable
data a ~ b = Eq# (a ~# b) () :: (a~b) -> a -> b x c = case c of Eq# d -> x # d refl :: t~t refl = /\t. Eq# (refl# t)
Library code Inline + optimise
let c7 = refl Bool in (x c7) && False ...inline refl, = (x # (refl# Bool)) && False
-
User API, and type inference, involves only the lifted (boxed) constraint type (a~b).
Major benefit (for SLPJ): all forms of evidence are treated uniformly f :: (Eq a, a ~ F b, Num b) => a -> b -> b
System FC (the intermediate language), has coercion stuff: (~#) and (#). [TLDI07]
Like types, the FC coercion stuff is fully erasable – guaranteed zero overhead.
Ordinary, unchanged optimisation removes (almost) all the overhead of boxed coercions.
Everyone is happy. World peace breaks out.