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: ch8.md
+14-9Lines changed: 14 additions & 9 deletions
Original file line number
Diff line number
Diff line change
@@ -170,11 +170,11 @@ A hammer is meant to be swung in your hand; if you instead hold it in your mouth
170
170
171
171
### A Word: Functors
172
172
173
-
We've mostly tried to stay away from artificial invented terminology in FP as much as possible in this book. We have used official terms at times, but mostly when we can derive some sense of meaning from them in regular everyday conversation.
173
+
We've mostly tried to stay away from invented terminology in FP as much as possible in this book. We have used official terms at times, but mostly when we can derive some sense of meaning from them in regular everyday conversation.
174
174
175
-
I'm going to very briefly break that pattern and use a word that might be a little intimidating: functor. The reason I want to talk about functors here is because we now already understand what they do, and because that term is used heavily throughout the rest of FP literature; you being at least familiar with and not scared by it will be beneficial.
175
+
I'm going to very briefly break that pattern and use a word that might be a little intimidating: functor. The reason I want to talk about functors here is because we now already understand what they do, and because that term is used heavily throughout the rest of FP literature; indeed, functors are foundational ideas in FP that come straight from the mathematical principles (category theory). You being at least familiar with and not scared by this term will be beneficial.
176
176
177
-
A functor is a value that has a utility for using an operator function on that value.
177
+
A functor is a value that has a utility for using an operator function on that value, which preserves composition.
178
178
179
179
If the value in question is compound, meaning it's comprised of individual values -- as is the case with arrays, for example! -- a functor uses the operator function on each individual value. Moreover, the functor utility creates a new compound value holding the results of all the individual operator function calls.
180
180
@@ -217,6 +217,8 @@ Does your view of filtering depend on whether the stuff you want is "kept" in th
217
217
218
218
What about on airline / hotel websites, when you specify options to "filter your results"? Are you filtering in the results that match your criteria, or are you filtering out everything that doesn't match? Think carefully: this example might have a different semantic than the previous ones.
219
219
220
+
### Filtering Confusion
221
+
220
222
Depending on your perspective, filter is either exclusionary or inclusionary. This conceptual conflation is unfortunate.
221
223
222
224
I think the most common interpretation of filtering -- outside of programming, anyway -- is that you filter out unwanted stuff. Unfortunately, in programming, we have essentially flipped this semantic to be more like filtering in wanted stuff.
@@ -353,7 +355,7 @@ I think using `filterIn(..)` and `filterOut(..)` (known as `reject(..)` in Ramda
353
355
354
356
While `map(..)` and `filter(..)` produce new lists, typically this third operator (`reduce(..)`) combines (aka "reduces") the values of a list down to a single finite (non-list) value, like a number or string. However, later in this chapter, we'll look at how you can push `reduce(..)` to use it in more advanced ways. `reduce(..)` is one of the most important FP tools; it's like a swiss army all-in-one knife with all its usefulness.
355
357
356
-
A combination/reduction is abstractly defined as taking two values and making them into one value. Some FP contexts refer to this as "folding", as if you're folding two values together into on value. That's a helpful visualization, I think.
358
+
A combination/reduction is abstractly defined as taking two values and making them into one value. Some FP contexts refer to this as "folding", as if you're folding two values together into one value. That's a helpful visualization, I think.
357
359
358
360
Just like with mapping and filtering, the manner of the combination is entirely up to you, and generally dependent on the types of values in the list. For example, numbers will typically be combined through arithmetic, strings through concatenation, and functions through composition.
359
361
@@ -1110,7 +1112,9 @@ Finally, to put it all together, take this list of functions and tack on the gua
1110
1112
1111
1113
Gone are all the imperative variable declarations and conditionals, and in their place we have clean and declarative list operations chained together.
1112
1114
1113
-
If this version is harder for you read right now than the original, don't worry. The original is unquestionably the imperative form you're probably more familiar with. Part of your evolution to become a functional programmer is to develop a recognition of FP patterns such as list operations. Over time, these will jump out of the code more readily as your sense of code readability shifts to declarative style.
1115
+
I know this version is likely harder for most readers to understand right now than the original. Don't worry, that's natural. The original imperative form is one you're probably much more familiar with.
1116
+
1117
+
Part of your evolution to become a functional programmer is to develop a recognition of FP patterns such as list operations, and that takes lots of exposure and practice. Over time, these will jump out of the code more readily as your sense of code readability shifts to declarative style.
1114
1118
1115
1119
Before we leave this topic, let's take a reality check: the example here is heavily contrived. Not all code segments will be straightforwardly modeled as list operations. The pragmatic take-away is to develop the instinct to look for these opportunities, but not get too hung up on code acrobatics; some improvement is better than none. Always step back and ask if you're **improving or harming** code readability.
1116
1120
@@ -1222,15 +1226,15 @@ Just as we said earlier that array's `map(..)` adapts a single-value operation t
1222
1226
1223
1227
The important part to maintain in the spirit of FP is that these operators must behave according to value immutability, meaning that they must return a new data structure rather than mutating the existing one.
1224
1228
1225
-
Let's illustrate with a well-known data structure: the binary tree. A binary tree is a node (just an object!) that has two references to other nodes (themselves binary trees), typically referred to as *left* and *right* child trees. Each node in the tree holds one value of the overall data structure.
1229
+
Let's illustrate with a well-known data structure: the binary tree. A binary tree is a node (just an object!) that has at most two references to other nodes (themselves binary trees), typically referred to as *left* and *right* child trees. Each node in the tree holds one value of the overall data structure.
1226
1230
1227
1231
<p align="center">
1228
1232
<img src="fig7.png" width="250">
1229
1233
</p>
1230
1234
1231
1235
For ease of illustration, we'll make our binary tree a binary search tree (BST). However, the operations we'll identify work the same for any regular non-BST binary tree.
1232
1236
1233
-
**Note:** A binary search tree is a general binary tree with a special constraint on the relationship of values in the tree to each other. Each value of nodes on the left side of a tree is less than the value of the node at the root of that tree, which in turn is less than each value of nodes in the right side of the tree. The notion of "less than" is relative to the kind of data stored; it can be numerical for numbers, lexicographic for strings, etc. BSTs are useful because they make searching for a value in the tree straightforward and more efficient, using a recursive binary search algorithm.
1237
+
**Note:** A binary search tree is a general binary tree with a special constraint on the relationship of values in the tree to each other. Each value of nodes on the left side of a tree is less than the value of the node at the root of that tree, which in turn is less than each value of nodes in the right side of the tree. The notion of "less than" is relative to the kind of data stored; it can be numerical for numbers, lexicographic for strings, etc. BSTs by definition must remain balanced, which makes searching for a value in the tree more efficient, using a recursive binary search algorithm.
1234
1238
1235
1239
To make a binary tree node object, let's use this factory function:
1236
1240
@@ -1468,7 +1472,6 @@ BinaryTree.filter = function filter(predicateFn,node){
1468
1472
}
1469
1473
};
1470
1474
```
1471
-
1472
1475
The majority of this code listing is dedicated to handling the shifting of a node's parent/child references if it's "removed" (filtered out) of the duplicated tree structure.
1473
1476
1474
1477
As an example to illustrate using `filter(..)`, let's narrow our produce tree down to only vegetables:
@@ -1493,11 +1496,13 @@ BinaryTree.reduce(
1493
1496
// ["avocado","cucumber"]
1494
1497
```
1495
1498
1499
+
**Note:** We aren't making any effort to rebalance a tree after any of the `map` / `reduce` / `filter` operations on BSTs. Technically, this means the results are not themselves binary *search* trees. Most JS values have a reasonable `<` less-than operation by which we could rebalance such a tree, but some values (like promises) wouldn't have any such definition. For the sake of keeping this chapter practical in length, we'll punt on handling this complication.
1500
+
1496
1501
You will likely use most of the list operations from this chapter in the context of simple arrays. But now we've seen that the concepts apply to whatever data structures and operations you might need. That's a powerful expression of how FP can be widely applied to many different application scenarios!
1497
1502
1498
1503
## Summary
1499
1504
1500
-
Three common and powerful list operations:
1505
+
Three common and powerful list operations we looked at:
1501
1506
1502
1507
* `map(..)`: transforms values as it projects them to a new list.
1503
1508
* `filter(..)`: selects or excludes values as it projects them to a new list.
0 commit comments