You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/syntax-in-functions.html
+38-42Lines changed: 38 additions & 42 deletions
Original file line number
Diff line number
Diff line change
@@ -222,45 +222,41 @@ <h1 style="margin-left:-3px">Syntax in Functions</h1>
222
222
</pre>
223
223
<divclass="hintbox"><em>Note:</em> Not only can we call functions as infix with backticks, we can also define them using backticks. Sometimes it's easier to read that way.</div>
224
224
<aname="where"></a><h2>Where!?</h2>
225
-
<p>In the previous section, we defined a BMI calculator function and berator like this:</p>
225
+
<p>In the previous section, we defined a density calculator function and responder like this:</p>
226
226
<prename="code" class="haskell:hs">
227
-
bmiTell :: (RealFloat a) => a -> a -> String
<p>Notice that we repeat ourselves here three times. We repeat ourselves three times. Repeating yourself (three times) while programming is about as desirable as getting kicked inna head. Since we repeat the same expression three times, it would be ideal if we could calculate it once, bind it to a name and then use that name instead of the expression. Well, we can modify our function like this:</p>
227
+
densityTell :: (RealFloat a) => a -> a -> String
228
+
densityTell mass volume
229
+
| mass / volume < 1.2 = "Wow! You're going for a ride in the sky!"
230
+
| mass / volume <= 1000.0 = "Have fun swimming, but watch out for sharks!"
231
+
| otherwise = "If it's sink or swim, you're going to sink."
232
+
</pre>
233
+
<p>Notice that we repeat ourselves here two times. We repeat ourselves two times. Repeating yourself (two times) while programming is about as desirable as getting kicked inna head. Since we repeat the same expression twice, it would be ideal if we could calculate it once, bind it to a name and then use that name instead of the expression. Well, we can modify our function like this:</p>
235
234
<prename="code" class="haskell:hs">
236
-
bmiTell :: (RealFloat a) => a -> a -> String
237
-
bmiTell weight height
238
-
| bmi <= 18.5 = "You're underweight, you emo, you!"
239
-
| bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"
<p>We put the keyword <spanclass="fixed">where</span> after the guards (usually it's best to indent it as much as the pipes are indented) and then we define several names or functions. These names are visible across the guards and give us the advantage of not having to repeat ourselves. If we decide that we want to calculate BMI a bit differently, we only have to change it once. It also improves readability by giving names to things and can make our programs faster since stuff like our <spanclass="fixed">bmi</span> variable here is calculated only once. We could go a bit overboard and present our function like this:</p>
235
+
densityTell :: (RealFloat a) => a -> a -> String
236
+
densityTell mass volume
237
+
| density < 1.2 = "Wow! You're going for a ride in the sky!"
238
+
| density <= 1000.0 = "Have fun swimming, but watch out for sharks!"
239
+
| otherwise = "If it's sink or swim, you're going to sink."
240
+
where density = mass / volume
241
+
</pre>
242
+
<p>We put the keyword <spanclass="fixed">where</span> after the guards (usually it's best to indent it as much as the pipes are indented) and then we define several names or functions. These names are visible across the guards and give us the advantage of not having to repeat ourselves. If we decide that we want to calculate density a bit differently, we only have to change it once. It also improves readability by giving names to things and can make our programs faster since stuff like our <spanclass="fixed">density</span> variable here is calculated only once. We could go a bit overboard and present our function like this:</p>
245
243
<prename="code" class="haskell:hs">
246
-
bmiTell :: (RealFloat a) => a -> a -> String
247
-
bmiTell weight height
248
-
| bmi <= skinny = "You're underweight, you emo, you!"
249
-
| bmi <= normal = "You're supposedly normal. Pffft, I bet you're ugly!"
densityTell :: (RealFloat a) => a -> a -> String
245
+
densityTell mass volume
246
+
| density < air = "Wow! You're going for a ride in the sky!"
247
+
| density <= water = "Have fun swimming, but watch out for sharks!"
248
+
| otherwise = "If it's sink or swim, you're going to sink."
249
+
where density = mass / volume
250
+
air = 1.2
251
+
water = 1000.0
256
252
</pre>
257
253
<p>The names we define in the where section of a function are only visible to that function, so we don't have to worry about them polluting the namespace of other functions. Notice that all the names are aligned at a single column. If we don't align them nice and proper, Haskell gets confused because then it doesn't know they're all part of the same block.</p>
258
254
<p><i>where</i> bindings aren't shared across function bodies of different patterns. If you want several patterns of one function to access some shared name, you have to define it globally.</p>
259
255
<p>You can also use where bindings to <em>pattern match</em>! We could have rewritten the where section of our previous function as:</p>
260
256
<prename="code" class="haskell:hs">
261
257
...
262
-
where bmi = weight / height ^ 2
263
-
(skinny, normal, fat) = (18.5, 25.0, 30.0)
258
+
where density = mass / volume
259
+
(air, water) = (1.2, 1000.0)
264
260
</pre>
265
261
<p>Let's make another fairly trivial function where we get a first and a last name and give someone back their initials.</p>
266
262
<prename="code" class="haskell:hs">
@@ -270,13 +266,13 @@ <h1 style="margin-left:-3px">Syntax in Functions</h1>
270
266
(l:_) = lastname
271
267
</pre>
272
268
<p>We could have done this pattern matching directly in the function's parameters (it would have been shorter and clearer actually) but this just goes to show that it's possible to do it in where bindings as well.</p>
273
-
<p>Just like we've defined constants in where blocks, you 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.</p>
269
+
<p>Just like we've defined constants in where blocks, you can also define functions. Staying true to our solids programming theme, let's make a function that takes a list of mass-volume pairs and returns a list of densities.</p>
274
270
<prename="code" class="haskell:hs">
275
-
calcBmis :: (RealFloat a) => [(a, a)] -> [a]
276
-
calcBmis xs = [bmi w h | (w, h) <- xs]
277
-
where bmi weight height = weight / height ^ 2
271
+
calcDensities :: (RealFloat a) => [(a, a)] -> [a]
272
+
calcDensities xs = [density m v | (m, v) <- xs]
273
+
where density mass volume = mass / volume
278
274
</pre>
279
-
<p>And that's all there is to it! The reason we had to introduce <spanclass="fixed">bmi</span> as a function in this example is because we can't just calculate one BMI from the function's parameters. We have to examine the list passed to the function and there's a different BMI for every pair in there.</p>
275
+
<p>And that's all there is to it! The reason we had to introduce <spanclass="fixed">density</span> as a function in this example is because we can't just calculate one density from the function's parameters. We have to examine the list passed to the function and there's a different density for every pair in there.</p>
280
276
<p><i>where</i> bindings can also be nested. It's a common idiom to make a function and define some helper function in its <i>where</i> clause and then to give those functions helper functions as well, each with its own <i>where</i> clause.</p>
281
277
<aname="let-it-be"></a><h2>Let it be</h2>
282
278
<p>
@@ -318,17 +314,17 @@ <h1 style="margin-left:-3px">Syntax in Functions</h1>
318
314
ghci> (let (a,b,c) = (1,2,3) in a+b+c) * 100
319
315
600
320
316
</pre>
321
-
<p>You can also put <i>let</i> bindings inside list comprehensions. Let's rewrite our previous example of calculating lists of weight-height pairs to use a <i>let</i> inside a list comprehension instead of defining an auxiliary function with a <i>where</i>.</p>
317
+
<p>You can also put <i>let</i> bindings inside list comprehensions. Let's rewrite our previous example of calculating lists of mass-volume pairs to use a <i>let</i> inside a list comprehension instead of defining an auxiliary function with a <i>where</i>.</p>
322
318
<prename="code" class="haskell:hs">
323
-
calcBmis :: (RealFloat a) => [(a, a)] -> [a]
324
-
calcBmis xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2]
319
+
calcDensities :: (RealFloat a) => [(a, a)] -> [a]
320
+
calcDensities xs = [density | (m, v) <- xs, let density = m / v]
325
321
</pre>
326
-
<p>We include a <i>let</i> inside a list comprehension much like we would a predicate, only it doesn't filter the list, it only binds to names. The names defined in a <i>let</i> inside a list comprehension are visible to the output function (the part before the <spanclass="fixed">|</span>) and all predicates and sections that come after of the binding. So we could make our function return only the BMIs of fat people:</p>
322
+
<p>We include a <i>let</i> inside a list comprehension much like we would a predicate, only it doesn't filter the list, it only binds to names. The names defined in a <i>let</i> inside a list comprehension are visible to the output function (the part before the <spanclass="fixed">|</span>) and all predicates and sections that come after of the binding. So we could make our function return only the densities that will float in air:</p>
327
323
<prename="code" class="haskell:hs">
328
-
calcBmis :: (RealFloat a) => [(a, a)] -> [a]
329
-
calcBmis xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2, bmi >= 25.0]
324
+
calcDensities :: (RealFloat a) => [(a, a)] -> [a]
325
+
calcDensities xs = [density | (m, v) <- xs, let density = m / v, density < 1.2]
330
326
</pre>
331
-
<p>We can't use the <spanclass="fixed">bmi</span> name in the <spanclass="fixed">(w, h) <- xs</span> part because it's defined prior to the <i>let</i> binding.</p>
327
+
<p>We can't use the <spanclass="fixed">density</span> name in the <spanclass="fixed">(m, v) <- xs</span> part because it's defined prior to the <i>let</i> binding.</p>
332
328
<p>We omitted the <i>in</i> part of the <i>let</i> binding when we used them in list comprehensions because the visibility of the names is already predefined there. However, we could use a <i>let in</i> binding in a predicate and the names defined would only be visible to that predicate. The <i>in</i> part can also be omitted when defining functions and constants directly in GHCi. If we do that, then the names will be visible throughout the entire interactive session.</p>
0 commit comments