#RTIMG# mjd.jpg Atypical Types ============== v 1.0 +++++ Mark Jason Dominus ================== 23 October 2008 +++++++++++++++ Slides online at: #HTML#

http://pic.blog.plover.com/OOPSLA/  #HTML# Philip Wadler Martin Odersky #HTML# (University of Edinburgh) (EPFL) #HTML#
---------------------------------------------------------------- 1999 vs. Today ************** #HTML# #HTML#  #HTML# Philip Wadler Martin Odersky #HTML#
 fact :: (Num a) => a -> b #HTML#
"[] has type [[(Num _a_) => _a_]]." fact 0 = 1 fact [C[n]C] = n * fact(n-1) "So [[_n_]] must have that type too." ---------------------------------------------------------------- Type inference ************** #HTML# #HTML#
 fact :: (Num a) => a -> b #HTML# n :: (Num a) => a #HTML#
"[] has type [[(Num _a_) => _a_]]." "So [[_n_]] must have that type too." fact 0 = 1 fact n = n * fact([C[n-1]C]) "[[_n_-1]] checks out okay." ---------------------------------------------------------------- Type inference ************** #HTML# #HTML#
 fact :: (Num a) => a -> b #HTML# n :: (Num a) => a #HTML#
"[[_n_]] has type [[(Num _a_) => _a_]]." fact 0 = 1 fact n = [C[n * fact(n-1)]C] "[[*]] requires two arguments of the same type, both instances of [[Num]]." "So [[fact]] must return [[(Num _a_) => _a_]] also." ---------------------------------------------------------------- Type inference ************** #HTML# #HTML#
 fact :: (Num a) => a -> a #HTML# n :: (Num a) => a #HTML#
"[[fact]] must return [[(Num _a_) => _a_]] also." fact 0 = [CC] fact n = n * fact(n-1) "The return value of [] is consistent with that." ---------------------------------------------------------------- Type inference ************** #HTML# #HTML#
 fact :: (Num a) => a -> a #HTML# n :: (Num a) => a #HTML#
fact 0 = 1 fact n = n * fact(n-1) "Okay, everything checks out!" o And if you ask it, it will _tell you_ the type of [[fact]]: fact :: (Num _a_) => _a_ -> _a_ o If you ask for the factorial of an [[Integer]], you get back an [[Integer]] o If you ask for the factorial of a [[Float]], you get back a [[Float]] o If you ask for the factorial of a [[String]], you get a compile-time error o Because [[String]] is not an instance of [[Num]] ---------------------------------------------------------------- Haskell types are always correct ******************************** fact :: (Num _a_) => _a_ -> _a_ o Ask the compiler to tell you the type of some function o Is it what you expect? o Yes? Okay then! o If not, your program almost certainly has a bug. o A _real_ bug, not a nonsense string-the-wrong-length bug ---------------------------------------------------------------- Haskell types are always correct ******************************** #IMG# cast.jpg o When there's a type error, you do not have to groan and pull out a bunch of casts o Or figure out to trick the compiler into accepting it anyway o Instead, you stop and ask yourself "What did I screw up this time?" o And when you figure it out, you say "Whew! Good thing I caught that." ---------------------------------------------------------------- Type Inference Example 2 ************************ sumof [] = 0 sumof (h:t) = h + sumof t ---------------------------------------------------------------- Type Inference ************** sumof [C[??![]??!]C] = 0 sumof (h:t) = h + sumof t "The argument is [[??![]??!]]." "That's some kind of list, say [[??![_a_]??!]]." "And let's say that the return type is [[_b_]] for now." ---------------------------------------------------------------- Type Inference ************** #HTML# #HTML#
 sumof :: [a] -> b #HTML#
"The argument has type [[??![_a_]??!]]." sumof [] = 0 sumof ([C[h:t]C]) = h + sumof t "[[h:t]] is also a list, so that's okay." "[[h]] must have type [[_a_]] and [[t]] must have type [[??![_a_]??!]]." h :: _a_ t :: [[??![_a_]??!]] ---------------------------------------------------------------- Type Inference ************** #HTML# #HTML#
 sumof :: [a] -> b #HTML# h :: a #HTML# t :: [a] #HTML#
"[[h]] must have type [[_a_]] and [[t]] must have type [[??![_a_]??!]]." sumof [] = 0 sumof (h:t) = [C[h + sumof t]C] "We're adding [[h]] to the return value of [[sumof]]." "So the return value must be [[_a_]] also." "And [[+]] is only defined for instances of [[Num]], so [[_a_]] is such an instance "So the return value is really of type (Num _a_) => _a_." sumof :: (Num [[_a_]]) => [[??![_a_]??!]] -> [[_a_]] ---------------------------------------------------------------- Type Inference ************** #HTML# #HTML#
 sumof :: (Num a) => [a] -> a #HTML# h :: (Num a) => a #HTML# t :: (Num a) => [a] #HTML#
"So the return value is really (Num _a_) => _a_." sumof [] = [CC] sumof (h:t) = h + sumof t "That fits with the other return value of 0." "And everything else checks out okay." o If you ask, it will say that the type is: sumof :: (Num _a_) => [_a_] -> _a_ o If we had put [[0.0]] instead of 0, it would have deduced: sumof :: (Fractional _a_) => [_a_] -> _a_ o ([[Fractional]] is a subclass of [[Num]]) o Among other things, it supports division o If we had put [["Fred"]] we would have gotten a type error o Because [[String]] is not an instance of [[Num]] ---------------------------------------------------------------- Type Inference Example 3 ************************ map(f, []) = [] map(f, h:t) = f(h) : map(f, t) ---------------------------------------------------------------- Type Inference ************** map([C[f, []??!]C]) = [] map(f, h:t) = f(h) : map(f, t) "[[f]] has some type, say [[_p_]], and [[??![]??!]] has some list type, say [[??![_a_]??!]]." ---------------------------------------------------------------- Type Inference ************** #HTML# #HTML#
 map :: (p, [a]) -> q #HTML# f :: p #HTML#
"[[??![]??!]] has some list type, say [[??![_a_]??!]]." map(f, []) = [] map(f, [C[h:t]C]) = f(h) : map(f, t) "[[h]] must have type [[_a_]] and [[t]] must have type [[??![_a_]??!]]." ---------------------------------------------------------------- Type Inference ************** #HTML# #HTML#
 map :: (p, [a]) -> q #HTML# f :: p #HTML# h :: a #HTML# t :: [a] #HTML#
"[[h]] must have type [[_a_]]." map(f, []) = [] map(f, h:t) = [C[f(h)]C] : map(f, t) "[[f]] is used as a function applied to [[h]]." "So [[f]] must have type [[_a_ -> _b_]] for some [[_b_]]." "[[f]] must take an argument of type [[_a_]] and return a result of type [[_b_]]." ---------------------------------------------------------------- Type Inference ************** #HTML# #HTML#
 map :: (a -> b, [a]) -> q #HTML# f :: a -> b #HTML# h :: a #HTML# t :: [a] #HTML#
"[[f]] must take an argument of type [[_a_]] and return a result of type [[_b_]]." map(f, []) = [] map(f, h:t) = f(h) : [C[map(f, t)]C] "The result of [[f]] is consed to the result of [[map]]." "So [[map]] must return [[??![_b_]??!]]." ---------------------------------------------------------------- Type Inference ************** #HTML# #HTML#
 map :: (a -> b, [a]) -> [b] #HTML# f :: a -> b #HTML# h :: a #HTML# t :: [a] #HTML#
"[[map]] must return [[??![_b_]??!]]." map(f, []) = [C[ [] ]C] map(f, h:t) = f(h) : [map(f, t) "That fits with the return value in the other clause." "Everything else checks out okay." o If you ask the compiler, it will say that the type is: map :: (_a_ -> _b_, [_a_]) -> [_b_] ---------------------------------------------------------------- Type Inference Example 3 Continued ********************************** map :: (_a_ -> _b_, [_a_]) -> [_b_] Normally [[map]] is defined as a _curried_ function Instead of this: map(f, []) = [] map(f, h:t) = f(h) : map(f, t) We write this: map f [] = [] map f (h:t) = f(h) : map f t And the type is: map :: (_a_ -> _b_) -> [_a_] -> [_b_] Then for example: length :: [a] -> Integer map length ["I", "like", "pie"] [C[??![1, 4, 3]??!]C] length_all = map length length_all :: [??![a]??!] -> [Integer] length_all ["I", "like", "pie"] [C[??![1, 4, 3]??!]C] ---------------------------------------------------------------- Life with Haskell ***************** The Haskell type system has a lot of unspectacular successes. Programming in Haskell is pleasant o No type declarations[E[mdash]E]everything is automatic o You get quite a few type errors (darn!) o But _every error_ indicates a real, _serious_ problem o Not like [[lint]] or C or Pascal. ---------------------------------------------------------------- A Spectacular Example ********************* Here's a _spectacular_ example, due to Andrew R. Koenig. We will write a merge sort function. Strategy: o Split list into two lists o Sort each list separately o Merge sorted lists together We expect the type of this function to be (Ord _a_) => [_a_] -> [_a_] ---------------------------------------------------------------- Splitting ********* split [] = ([], []) split [a] = ([a], []) split (a:b:rest) = (a:a', b:b') where (a', b') = split rest split :: [_t_] -> ([_t_], [_t_]) ---------------------------------------------------------------- Merging ******* merge [] ls = ls merge ls [] = ls merge (a:as) (b:bs) = if a <= b then a : merge as (b:bs) else b : merge (a:as) bs merge :: (Ord _t_) => [_t_] -> [_t_] -> [_t_] ---------------------------------------------- Merge Sort ********** sort [] = [] sort ls = merge (sort p) (sort q) where (p, q) = split ls * If we ask Haskell for the type of [[sort]], it says: sort :: (Ord _a_) => [_t_] -> [_a_] #HTML#

Huh??

---------------------------------------------------------------- #HTML#

Huh??

sort :: (Ord _a_) => [_t_] -> [_a_] * This says that we could put in _any_ kind of list [[??![_t_]??!]] * It does not even have to be ordered * And what we get out has nothing to do with what we put in * We could put in a list of [[Integer]] and get out a list of [[String]] * Which is impossible ---------------------------------------------- #HTML#

Huh??

sort :: (Ord _a_) => [_t_] -> [_a_] * But this is _impossible_ One way the impossible can occur is if it never can occur ---------------------------------------------------------------- #LTIMG# gagme.jpg [E[ldquo]E]Go out with you? Sure, when [L[Arnold Schwarzenegger]L] is elected [L[president]L].[E[rdquo]E] [E[ldquo]E]But he isn't an American citizen.[E[rdquo]E] [E[ldquo]E]Right![E[rdquo]E] ---------------------------------------------- Huh??? ****** sort :: (Ord _a_) => [_t_] -> [_a_] [E[ldquo]E]Given a list of numbers, it could return a list of strings.[E[rdquo]E] [E[ldquo]E]But it can't possibly return a list of strings.[E[rdquo]E] [E[ldquo]E]Right![E[rdquo]E] ---------------------------------------------------------------- sort [] = [] sort ls = merge (sort p) (sort q) where (p, q) = split ls In fact, this function has a bug. * It never returns * (Except when the input is empty.) * (In which case it _does_ return a list of type [[??![_a_]??!]]) * _Type checking_ found an infinite loop bug! ================================================================ * At compile time!! ================================================================ * !!!!!!!!!! ---------------------------------------------------------------- Where's the Bug? **************** sort [] = [] sort ls = merge (sort p) (sort q) where (p, q) = split ls #LTIMG# bug2.jpg Suppose the function is trying to sort a one-element list [[??![x]??!]] It calls [[split]] and gets [[([x], [])]] Then it tries to recursively sort the two parts Sorting [[??![]??!]] is okay. Sorting [[??![x]??!]] puts it into an infinite loop ---------------------------------------------------------------- Solution: Add a clause sort [] = [] #* sort [x] = [x] sort ls = merge (sort p) (sort q) where (p, q) = split ls The type is now: sort :: (Ord _a_) => [_a_] -> [_a_] as we expected it should be. ---------------------------------------------------------------- Summary ******* #HTML#
#HTML# #HTML#
Ten years ago, this evolution seemed very unlikely to almost everyone But those dweeby guys have some very good ideas Also, they are the guys writing the compilers So pay attention, because I think the trend will continue ---------------------------------------------------------------- #RTIMG# sen.jpg Thank you! ********** They say to allot 3[E[ndash]E]5 minutes per slide So I won't pretend that there will be time for questions (sorry) Please email me or catch me in the hallway #HTML#

http://pic.blog.plover.com/OOPSLA/

#HTML#

mjd@plover.com

---------------------------------------------------------------- ----------------------------------------------------------------END ----------------------------------------------------------------