Online Book Reader

Home Category

Learn You a Haskell for Great Good! - Miran Lipovaca [20]

By Root 457 0
Pffft, I bet you're ugly!"

| bmi <= fat = "You're fat! Lose some weight, fatty!"

| otherwise = "You're a whale, congratulations!"

where bmi = weight / height ^ 2

skinny = 18.5

normal = 25.0

fat = 30.0

Note

Notice that all the variable names are aligned in a single column. If you don’t align them like this, Haskell will get confused, and it won’t know that they’re all part of the same block.

where's Scope


The variables we define in the where section of a function are visible only to that function, so we don’t need to worry about them polluting the namespace of other functions. If we want to use a variable like this in several different functions, we must define it globally.

Also, where bindings are not shared across function bodies of different patterns. For instance, suppose we want to write a function that takes a name and greets the person nicely if it recognizes that name, but not so nicely if it doesn’t. We might define it like this:

greet :: String -> String greet "Juan" = niceGreeting ++ " Juan!"

greet "Fernando" = niceGreeting ++ " Fernando!"

greet name = badGreeting ++ " " ++ name

where niceGreeting = "Hello! So very nice to see you,"

badGreeting = "Oh! Pfft. It's you."

This function won’t work as written. Because where bindings aren’t shared across function bodies of different patterns, only the last function body sees the greetings defined by the where binding. To make this function work correctly, badGreeting and niceGreeting must be defined globally, like this:

badGreeting :: String

badGreeting = "Oh! Pfft. It's you."

niceGreeting :: String

niceGreeting = "Hello! So very nice to see you,"

greet :: String -> String

greet "Juan" = niceGreeting ++ " Juan!"

greet "Fernando" = niceGreeting ++ " Fernando!"

greet name = badGreeting ++ " " ++ name

Pattern Matching with where


You can also use where bindings to pattern match. We could have written the where section of our BMI function like this:

...

where bmi = weight / height ^ 2

(skinny, normal, fat) = (18.5, 25.0, 30.0)

As an example of this technique, let’s write a function that gets a first name and last name, and returns the initials:

initials :: String -> String -> String

initials firstname lastname = [f] ++ ". " ++ [l] ++ "."

where (f:_) = firstname

(l:_) = lastname

We could have also done this pattern matching directly in the function’s parameters (it would have been shorter and more readable), but this example shows that it’s possible to do it in the where bindings as well.

Functions in where Blocks


Just as we’ve defined constants in where blocks, we can also define functions. Staying true to our healthy programming theme, let’s make a function that takes a list of weight/height pairs and returns a list of BMIs:

calcBmis :: [(Double, Double)] -> [Double]

calcBmis xs = [bmi w h | (w, h) <- xs]

where bmi weight height = weight / height ^ 2

And that’s all there is to it! The reason we needed to introduce bmi as a function in this example is that we can’t just calculate one BMI from the function’s parameters. We need to examine the list passed to the function, and there’s a different BMI for every pair in there.

let It Be

let expressions are very similar to where bindings. where allows you bind to variables at the end of a function, and those variables are visible to the entire function, including all its guards. let expressions, on the other hand, allow you to bind to variables anywhere and are expressions themselves. However, they’re very local, and they don’t span across guards. Just like any Haskell construct that’s used to bind values to names, let expressions can be used in pattern matching.

Now let’s see let in action. The following function returns a cylinder’s surface area, based on its height and radius:

cylinder :: Double -> Double -> Double

cylinder r h =

let sideArea = 2 * pi * r * h

topArea = pi * r ^ 2

in sideArea + 2 * topArea

let expressions take the form of let in . The variables that you define with let are visible within the entire let expression.

Return Main Page Previous Page Next Page

®Online Book Reader