[Completed editing pass over ch03 Bryan O'Sullivan **20080320064300] { hunk ./en/ch03-funcs-types.xml 609 - Understanding a function's type signature + Function types and purity hunk ./en/ch03-funcs-types.xml 624 - The \n in the input string is an - escaped newline (line ending) character: - lines splits a string on line boundaries. - Notice that its type signature gave us a strong hint as to what - the function might actually do. This is an incredibly valuable - property of types in a functional language. + The lines function splits a + string on line boundaries. Notice that its type signature gave + us a hint as to what the function might actually do: it takes + one String, and returns many. This is an + incredibly valuable property of types in a functional + language. hunk ./en/ch03-funcs-types.xml 631 - A side effect modifies the state of the - system, for example by reading or writing a file. Most Haskell - functions can't cause side effects, so we refer to them as - pure. The result of applying a pure - function can only depend on its arguments. We can often get a - strong hint of what a pure function does by simply reading its - name and understanding its type signature. As an example, let's - look at not. + A side effect introduces a + dependency between the global state of the system and the + behaviour of a function. For example, let's step away from + Haskell for a moment and think about an imperative programming + language. Consider a function that reads and returns the value + of a global variable. If some other code can modify that global + variable, then the result of a particular application of our + function depends on the current value of the global variable. + The function has a side effect, even though it never modifies + the variable itself. hunk ./en/ch03-funcs-types.xml 642 - &func.ghci:not.type; + Side effects are essentially invisible inputs to, or outputs + from, functions. In Haskell, the default is for functions to + not have side effects: the result of a + function depends only on the inputs that we explicitly provide. + We call these functions pure; functions + with side effects are impure. hunk ./en/ch03-funcs-types.xml 649 - Even if we didn't know the name of this function, its - signature alone limits the possible valid behaviours it could - have. + If a function has side effects, we can tell by reading its + type signature: the type of the function's result will begin + with IO. hunk ./en/ch03-funcs-types.xml 653 - - - Ignore its argument, and always return either - True or False. - - - Return its argument unmodified. - - - Negate its argument. - - + &ch03.basics.ghci:readFile; + + Haskell's type system prevents us from accidentally mixing + pure and impure code. hunk ./en/ch03-funcs-types.xml 1196 + + A visual tour + + Create a series of graphics showing the reduction + process. + + hunk ./en/ch03-funcs-types.xml 1221 - The result of applying a function may be an expression - whose evaluation has been deferred because it has not yet - been needed. + The result of applying a function may be a + thunk (a deferred expression). hunk ./en/ch03-funcs-types.xml 1237 - If we want to fetch the last element of a list, we use the - last function. The value that it returns - must have the same type as the elements of the list, but + If we want to fetch the last element of a list, we + use the last function. The value that it + returns must have the same type as the elements of the list, but hunk ./en/ch03-funcs-types.xml 1241 - what type those elements actually - are. + what type those elements actually are. hunk ./en/ch03-funcs-types.xml 1245 - To capture the idea that last needs its - argument and result types to be the same, but doesn't need to - know their details, its type signature contains a type - variable. + To capture this idea, its type signature contains + a type variable. hunk ./en/ch03-funcs-types.xml 1253 - returns a value of type When we want to apply last to, say, a - list of Char, we substitute Char for - each a throughout the type - signature, which gives us the type of - last-over-[Char] as - [Char] -> Char. + When we want to apply last + to, say, a list of Char, the compiler substitutes + Char for each a + throughout the type signature, which gives us the type of + last with an input of [Char] + as [Char] -> Char. hunk ./en/ch03-funcs-types.xml 1294 - If the type of a function contains type parameters, we can - call the function polymorphic, or say that it has a - parameterised type. This is also the case for types. + If a type contains type parameters, we say that + it is a parameterised type, or a polymorphic type. If a + function's type contains type parameters, we call the function + polymorphic. hunk ./en/ch03-funcs-types.xml 1300 - When a function or type has a parameterised type, we've - already noted that it doesn't care what the actual type is. + When we see a parameterised type, we've + already noted that the code doesn't care what the actual type is. hunk ./en/ch03-funcs-types.xml 1309 - Parametric polymorphism is the most visible kind of - polymorphism that Haskell supports. Here are a few forms of - polymorphism that are common in other languages, but not present - in Haskell. + Parametric polymorphism is the most visible kind + of polymorphism that Haskell supports. Haskell's parametric + polymorphism directly influenced the design of the generic + facilities of the Java and C# languages. A parameterised type + in Haskell is similar to a type variable in Java + generics. C++ templates also bear a resemblance to parametric + polymorphism. + + To make it clearer how Haskell's polymorphism differs from + other languages, here are a few forms of polymorphism that are + common in other languages, but not present in Haskell. hunk ./en/ch03-funcs-types.xml 1329 - Also common is coercion polymorphism, - which allows a value of one type to be implicitly converted into - a value of another type. Many languages provide some form of - coercion polymorphism: one example is automatic conversion - between integers and floating point numbers. Haskell avoids - even this kind of simple automatic coercion. + Also common is coercion + polymorphism, which allows a value of one type to be implicitly + converted into a value of another type. Many languages provide + some form of coercion polymorphism: one example is automatic + conversion between integers and floating point numbers. Haskell + deliberately avoids even this kind of simple automatic + coercion. hunk ./en/ch03-funcs-types.xml 1364 - only possible behaviour it can have is to + only possible valid behaviour (omitting + infinite loops or crashes) it can have is to hunk ./en/ch03-funcs-types.xml 1371 - We can extend this line of reasoning to more complicated - polymorphic functions. The paper covers this - procedure in depth. + There is a deep mathematical sense in which + any non-pathological function of type (a,b) -> + a must do exactly what fst + does. Moreover, this line of reasoning extends to more + complicated polymorphic functions. The paper + + covers this procedure in depth. + + It's been suggested that we should create a + theory box for discussions of the deep stuff, + and references to academic papers. hunk ./en/ch03-funcs-types.xml 1399 - parses this chain of arrows from right to left; that is, + groups this chain of arrows from right to left; that is, hunk ./en/ch03-funcs-types.xml 1412 - This is an intriguing idea, but it's not yet easy - to see just yet what its consequences might be. We'll return to - this topic in , once we've - spent a bit of time writing functions. + This is correct, but it's not easy to see what its + consequences might be. We'll return to this topic in , once we've spent + a bit of time writing functions. For now, we can treat the type + following the last -> as being the function's + return type, and the preceding types to be those of the + function's arguments. hunk ./en/ch03-funcs-types.xml 1436 - element of a list. Write a function - lastButOne, that returns the element - before the last. + element of a list. From reading the type alone, what are + the possible valid behaviours (omitting crashes and + infinite loops) that this function could have? What are a + few things that this function clearly cannot do? + + + + + + Write a function lastButOne, that + returns the element before the + last. hunk ./en/ch03-funcs-types.xml 1460 - hunk ./en/ch03-funcs-types.xml 1462 + + Why the fuss over purity? + + Few programming languages go as far as Haskell in insisting + that purity should be the default. This choice has profound and + valuable consequences. + + Because the result of applying a pure function can only + depend on its arguments, we can often get a strong hint of what + a pure function does by simply reading its name and + understanding its type signature. As an example, let's look at + not. + + &func.ghci:not.type; + + Even if we didn't know the name of this function, + its signature alone limits the possible valid behaviours it + could have. + + + + Ignore its argument, and always return either + True or False. + + + Return its argument unmodified. + + + Negate its argument. + + + + We also know that this function can not + do some things: it cannot access files; it cannot talk to the + network; it cannot tell what time it is. + + Purity makes the job of understanding code easier. The + behaviour of a pure function does not depend on the value of a + global variable, or the contents of a database, or the state of + a network connection. Pure code is inherently modular: every + function is self-contained, and has a well-defined + interface. + + A non-obvious consequence of purity being the default is + that working with impure code becomes + easier. Haskell encourages a style of programming in which we + separate code that must have side effects + from code that doesn't need them. In this style, impure code + tends to be simple, with the heavy lifting + performed in pure code. + + Much of the risk in software lies in talking to the outside + world, be it coping with bad or missing data, or handling + malicious attacks. Because Haskell's type system tells us + exactly which parts of our code have side effects, we can be + appropriately on our guard. Because our favoured coding style + keeps impure code isolated and simple, our attack + surface is small. + hunk ./en/ch03-funcs-types.xml 1529 - expressions, and how to reason about lazy evaluation. + expressions, purity, and about lazy evaluation. hunk ./examples/ch03/ch03.basics.ghci 11 +--# readFile + +:type readFile + }