[More work on ch03. Bryan O'Sullivan **20070717060534] { addfile ./examples/ch03/Roots.hs addfile ./examples/ch03/realRoots.ghci hunk ./en/ch03-funcs-types.xml 172 - importance. An example of this might be to represent a row - in the result of a a database query. + importance. An example of this might be to represent a row in + the result of a a database query. hunk ./en/ch03-funcs-types.xml 192 - function followed by its arguments, all separated by whitespace. + function followed by its arguments, all separated by white space. hunk ./en/ch03-funcs-types.xml 351 - expression. Let's see it in action: we'll write our own - version of the standard take function. - Before we do so, let's probe a little bit of how - take behaves. + expression. Let's see it in action, then we'll explain what's + going on. As an example, we'll write our own version of the + standard take function. Before we begin, + let's probe a little bit of how take + behaves, so we can replicate its behaviour. hunk ./en/ch03-funcs-types.xml 360 - removes at most the given number of elements from the front of - a list (it returns the empty list if the number to remove is - greater than the number of elements), and that it treats - negative numbers as zero. - - Here's a myTake function that has the - same behaviour as take, and uses - Haskell's if expression. + returns an empty list if the number to remove is greater than + the number of elements, and that it treats negative numbers as + zero. Here's a myTake function that has + the same behaviour, and uses Haskell's if + expression to decide what to do. hunk ./en/ch03-funcs-types.xml 407 + Third is that our function calls itself recursively. This + is an early example of how, in Haskell, we use recursion where + in an imperative language we'd probably use a loop. + hunk ./en/ch03-funcs-types.xml 415 - for example, but this is harder to read. + for example, but we'd end up with less readable code. hunk ./en/ch03-funcs-types.xml 494 + hunk ./en/ch03-funcs-types.xml 635 + + + Back to writing functions: local variables + + Let's take a break from writing about types for a few + moments. Within the body of a function, we can introduce new + local variables whenever we need them, using a let + expression. As an example, let's write a function that + calculates the real-valued roots of the quadratic equation + a * (x ** 2) + b * x + c == 0. + + &Roots.hs:realRoots; + + The keywords to look out for here are let, + which starts a block of variable declarations, and + in, which ends it. Each line introduces a new + variable. The name is on the left of the =, + and its value on the right. We can use these variables both + within our block of variable declarations and in the expression + that follows the in keyword. + + There's no problem with a variable earlier in a + let block referring to a later one, or even with + them referring to each other. + + We sneaked a previously unseen standard type, + Maybe, into our example. We use Maybe + when it might not make sense to return a normal result, for + example because a function's result is undefined for some + inputs. We use Just to say we have + a result, and the argument to + Just is that result. When we can't give a + result, we use Nothing, which takes no + arguments. + + &realRoots.ghci:maybe; + + Why do we need Maybe here? The real-valued + roots of a quadratic equation are infinity when + a, the coefficient of x ** + 2, is zero. + + &realRoots.ghci:a0; + + They're also not defined when b ** 2 - 4 * a * + c is negative, because we would need to use complex + numbers to represent a negative square root. + + &realRoots.ghci:complex; + + Otherwise, we can return a normal result, wrapped in + Just. + + &realRoots.ghci:just; + + + + + The offside rule, and white space in a function body + + In our definition of realRoots, the + left margin of our text wandered around quite a bit. This was + not an accident: in Haskell, white space has meaning. + hunk ./examples/ch03/Roots.hs 1 +import Data.Complex + +{-- snippet realRoots --} +realRoots :: Double -> Double -> Double -> Maybe (Double, Double) + +realRoots a b c = let n = b**2 - 4 * a * c + a2 = 2 * a + r1 = (-b + sqrt n) / a2 + r2 = (-b - sqrt n) / a2 + in if n > 0 && a /= 0 + then Just (r1, r2) + else Nothing +{-- /snippet realRoots --} + +roots :: Double -> Double -> Double + -> Either (Complex Double, Complex Double) (Double, Double) + +roots a b c = let n = b**2 - 4 * a * c + a2 = 2 * a + n' = n :+ 0 + b' = b :+ 0 + a2' = a2 :+ 0 + in if n > 0 + then Right ((-b + sqrt n) / a2, (-b - sqrt n) / a2) + else Left ((-b' + sqrt n') / a2', (-b' - sqrt n') / a2') hunk ./examples/ch03/realRoots.ghci 1 +--# maybe +Just "answer" +Nothing + +--# a0 + +:load Roots.hs +realRoots 0 1 2 + +--# complex + +realRoots 1 3 4 + +--# just + +realRoots 1 3 2 }