Lecture 10: Types, Type Checking, & Type Inference

Lecture 10: Types, Type Checking, & Type Inference

Lecture 10: Types, Type checking, & Type inference CSC 131 Spring, 2019 Kim Bruce Programming Language Rankings Top Combined 1 JavaScript 11 Swift 2 Java 12 Scala 3 Python 12 Shell 4 PHP 14 Go 5 C# 14 R 6 C++ 16 TypeScript 7 CSS 17 PowerShell 8 Ruby 18 Perl 9 C 19 Haskell 9 Objective-C 20 Lua Tiobe Index Changes over Time 2014 -> 2019 Scala #41 -> 29 Haskell #44 -> 39 ML #25 -> 48 Go #38 -> 18 Dart #42 -> 25 Scheme #48 -> 36 Objective C # 3 -> 10 Swift # 18 -> 20 Static Type Checking Type checking • Most statically typed languages also include • Static type-checkers for strongly-typed some dynamic checks. languages (i.e., rule out all “bad” programs) - array bounds. must be conservative: - Java’s instanceof - Rule out some programs without errors. - typecase or type casts • if (program-that-could-run-forever) { expression-w-type-error; • Pascal statically typed, but not strongly typed } else { - variant records (essentialy union types), dangling pointers expression-w-type-error; } • Haskell, ML, Java strongly typed • C, C++ not strongly typed Type Compatibility Structural Equivalence • When is x := y legal? Type T = Array [1..10] of Integer; Var A, B : Array [1..10] of Integer; • Can be subtle: C : Array [1..10] of Integer; T1 = record a : integer; b : real end; D : T; T2 = record c : integer; d : real end; E : T; T3 = record b : real; a : integer end; • Which are the same? • Name EquivalenceA (Ada) T = record info : integer; next : ^T end; U = record info : integer; next : ^V end; • Name Equivalence (Pascal, Modula-2, Java) V = record info : integer; next : ^U end; • Structural Equivalence (Modula-3, Java arrays only) Type Checking & Inference Formal Type-Checking Rules • Can rewrite more formally. • Write explicit rules. Let a, b be expressions • Expression may involve variables, so type check - if a, b:: Integer, wrt assignment E of types to variables. then a+b, a*b, a div b, a mod b:: Integer - E.g., E(x) = Integer, E(b) = Bool, ... - if a, b:: Integer then a < b, a = b, a > b : Bool Hypothesis E(x) = t –––––––––––––– - if a, b: Bool then a && b, a || b: Bool E |- x : t Conclusion - ... E |- a : int, E |- b : int –––––––––––––––––––––––––––– E |- a+b : int Can write formally Function Application: E |- f: σ → τ, E |- M : σ –––––––––––––––––––––– E |- f(M) : τ Function Definition: Haskell Type Inference E ∪ {v:σ} |- Block : τ –––––––––––––––––––––––– How does Haskel know what you meant? E |- fun (v:σ) Block : σ → τ Can write for al language constructs. Based on context fee grammar. Can read off type-checking algorithm. More later! Haskell Type Inference Examples of Type Inference 1. An identifier should be assigned the same type Use rules to deduce types: throughout its scope. • 2. In an “if-then-else” expression, the condition must have map = \ f -> \ l -> type Bool and the “then” and “else” portions must have if l == [] then [] the same type. The type of the expression is the type of else (f (head l)): (map f (tail l)) the “then” and “else” portions. map:: a b because function 3. A user-defined function has type a → b, where a is the - → type of the function’s parameter and b is the type of its - f :: a, \ l -> ... :: b, Thus b = c → d result. - l :: c, if l = [] then ... :: d 4.In a function application of the form f x, there must be types a and b such that f has type a → b, x has type a, - ... and the application itself has type b. @ = application Outcome of Type Inference λ :a ( , ) @ :b • Overconstrained: no solution Prelude> tail 7 @ :c <interactive>:1:5: No instance for (Num [a]) x arising from the literal `7' at <interactive>:1:5 f :d :e Possible fix: add an instance declaration for (Num [a]) In the first argument of `tail', namely `7' In the expression: tail 7 In the definition of `it': it = tail 7 • Underconstrained: polymorphic double(f,x) = f(f(x)) Uniquely determined or equivalently • double = \ (f,x) -> f(f(x)) Restrictions on ML/Haskell By the way, ... Polymorphism • Inference due to Hindley-Milner • Type (a → b) →([a] → [b]) stands for: • SML/Haskell type inference is doubly - ∀a. ∀b. (a → b) →([a] → [b]) exponential in the worst case! • Haskell functions may not take polymorphic arguments. E.g., no type: Can write down terms tn of length n such that • ∀b. ((∀a.(a → a)) →(b → b)) n - the length of the type of tn is of length 22 - define: foo f (x,y) = (f x, f y) • Luckily, it doesn’t matter in practice, - id z = z - no one writes terms whose type is exponential in the - foo id (7, True) -- gives type error! length of the term! - Type of foo is only (t -> s) -> (t, t) -> (s, s) Restrictions on Implicit Explicit Polymorphism Polymorphism Polymorphic types can be defined at top level or in let clauses, but can’t be used as arguments of functions Easy to type w/ explicit polymorphism: id x = x test (g: forall t.t -> t) = (g “ab”, g 17) in (id "ab", id 17) in test (\t => \(x:t) -> x) OK, but can't write test g = (g “ab”, g 17) Languages w/explicit polymorphism: Clu, Ada, C++, Eiffel, Java 5, C#, Scala, Grace Can’t find type of test w/unification. More general type inference is undecidable. Explicit Polymorphism Summary • Modern tendency: strengthen typing & avoid • Clu, Ada, C++, Java implicit holes, but leave explicit escapes • C++ macro expanded at link time rather than • Push errors closer to compile time by: compile time. - Require over-specification of types • Java compiles away polymorphism, but checks - Distinguishing between different uses of same type it statically. - Mandate constructs that eliminate type holes • Better implementations keep track of type - Minimizing or eliminating explicit pointers parameters. • Holy grail: Provide type safety, increase flexibility Polymorphism vs Overloading Why Overloading? • Parametric polymorphism • Many useful functions not parametric - Single algorithm may be given many types - List membership requires equality - Type variable may be replaced by any type • member: [w] -> w -> Bool (for “good” w) • Examples: hd, tail ::[t]->t , map::(a->b)->[a]->[b] - Sorting requires ordering • Overloading • sort: [w] -> [w] (for w supporting <,>,...) - A single symbol may refer to more than one algorithm. • What are problems in supporting it in a PL? - Each algorithm may have different type. - Static type inference makes it hard! - Choice of algorithm determined by type context. - Why are Haskell type classes a solution? • (+) has types Int → Int → Int and Float → Float → Float, but not t→t→t for arbitrary t. Overloading Arithmetic ML & Overloading • First try: allow fcns w/overloaded ops to define • Functions like +, * can be overloaded, but not multiple functions functions defined from them! 3 * 3 -- legal - square x = x * x • • 3.14 * 3.14 -- legal • versions for Int -> Int and Float -> Float • square x = x * x -- Int -> Int But then - • square 3 -- legal squares (x,y,z) = (square x, square y, square z) • • square 3.14 -- illegal • ... has 8 different versions!! - To get other functions, must include type: Too complex to support! - • squaref (x:float) = x * x -- float -> float Equality Type Classes • Proposed for Haskell in 1989. • Equality worse! - Only defined for types not containing functions, files, • Provide concise types to describe overloaded or abstract types -- why? functions -- avoiding exponential blow-up - Again restrict functions using == • Allow users to define functions using overloaded • ML ended up defining eq types, with special operations: +, *, <, etc. mark on type variables. • Allow users to declare new overloaded functions. - member: ‘‘a -> [‘‘a] -> Bool - Generalize ML’s eqtypes - Can’t apply to list of functions - Fit within type inference framework Recall ... Example Recall • Definition of quicksort & partition: • partition lThan (pivot, []) = ([],[]) class Order a where partition lThan (pivot, first : others) = (<) :: a -> a -> Bool let (>) :: a -> a -> Bool (smalls, bigs) = partition lThan (pivot, others) ... in if (lThan first pivot) then (first:smalls, bigs) • Implement w/dictionary: else (smalls, first:bigs) data OrdDict a = MkOrdDict (a -> a -> Bool) (a -> a -> • Allowed partition to be parametric Bool) ... - Steal this idea to pass overloaded functions! getLT (MkOrdDict lt gt ...) = lt - Implicitly pass argument with any overloaded getGT (MkOrdDict lt gt) = gt functions needed!! ... Using Dictionaries Instances partition dict (pivot, []) = ([],[]) partition dict (pivot, first : others) = let (smalls, bigs) = partition dict (pivot, others) • Declaration in if ((getLT dict) first pivot) - instance Show TrafficLight where then (first:smalls, bigs) show Red = "Red light" else (smalls, first:bigs) show Yellow = "Yellow light" show Green = "Green light" partition:: OrdDict a -> [a] -> ([a].[a]) - Creates dictionary for “show” Compiler adds dictionary parameter to al cals of partition. Reports type of partition (w/out lThan parameter) as (Ord a) => [a] -> ([a].[a]) Implementation Summary Multiple Dictionaries • Compiler translates each function using an overloaded symbol into function with extra parameter: the dictionary. • Example: • References to overloaded symbols are rewritten by the compiler to lookup the symbol in the dictionary. - squares :: (Num a, Num b, Num c) => (a, b, c) -> (a, b, c) • The compiler converts each type class declaration into a - squares(x,y,z) = (square x, square y, square z) dictionary type declaration and a set of selector functions. • goes to: The compiler converts each instance declaration into a • squares (da,db,dc) (x, y, z) = dictionary of the appropriate type. - (square da x, square db y, square dc z) • The compiler rewrites calls to overloaded functions to pass a dictionary. It uses the static, qualified type of the function to select the dictionary..

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    9 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us