Skip to content

Commit b141ee2

Browse files
committed
Additional edits to purescript-contrib#285
Wanted to make this a PR to a PR branch for easier commenting on proposed changes. purescript-contrib#285
1 parent 6f498f2 commit b141ee2

File tree

1 file changed

+25
-24
lines changed

1 file changed

+25
-24
lines changed

text/chapter3.md

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,13 @@ In the case of `insertEntry`, _eta conversion_ has resulted in a very clear defi
481481

482482
## Property Accessors
483483

484-
One common pattern is to use a function to access an individual fields (or "properties") of a record. An inline function to extract an `Address` from an `Entry` could be written as:
484+
One common pattern is to use a function to access individual fields (or "properties") of a record. An inline function to extract an `Address` from an `Entry` could be written as:
485485

486486
```haskell
487487
\entry -> entry.address
488488
```
489489

490-
PureScript provides an equivalent [_property accessor_](https://github.com/purescript/documentation/blob/master/language/Syntax.md#property-accessors) shorthand, where an underscore is followed by a field name, so the inline function above is equivalent to:
490+
PureScript also allows [_property accessor_](https://github.com/purescript/documentation/blob/master/language/Syntax.md#property-accessors) shorthand, where an underscore acts as the anonymous fuction argument, so the inline function above is equivalent to:
491491

492492
```haskell
493493
_.address
@@ -561,7 +561,7 @@ This type signature says that `findEntry` takes two strings, the first and last
561561
And here is the definition of `findEntry`:
562562

563563
```haskell
564-
findEntry firstName lastName book = head $ filter filterEntry book
564+
findEntry firstName lastName book = head (filter filterEntry book)
565565
where
566566
filterEntry :: Entry -> Boolean
567567
filterEntry entry = entry.firstName == firstName && entry.lastName == lastName
@@ -591,7 +591,7 @@ However, this chapter has also included examples of _infix_ [binary operators](h
591591
infix 4 eq as ==
592592
```
593593

594-
and therefore `entry.firstName == firstName` in `filterEntry` could be replaced with the `eq entry.firstName firstName`.
594+
and therefore `entry.firstName == firstName` in `filterEntry` could be replaced with the `eq entry.firstName firstName`. We'll cover a few more examples of defining infix operators later in this section.
595595

596596
There are situations where putting a prefix function in an infix position as an operator leads to more readable code. One example is the `mod` function:
597597

@@ -621,7 +621,7 @@ book3 = insertEntry john (insertEntry peggy (insertEntry ned emptyBook))
621621
book4 = john `insertEntry` (peggy `insertEntry` (ned `insertEntry` emptyBook))
622622
```
623623

624-
We can also define an operator alias/synonym for `insertEntry.` We'll arbitrarily choose `++` for this operator, give it a [precedence](https://github.com/purescript/documentation/blob/master/language/Syntax.md#precedence) of `5`, and make it right [associative](https://github.com/purescript/documentation/blob/master/language/Syntax.md#associativity) using `infixr`:
624+
We can also define an infix operator alias (or synonym) for `insertEntry.` We'll arbitrarily choose `++` for this operator, give it a [precedence](https://github.com/purescript/documentation/blob/master/language/Syntax.md#precedence) of `5`, and make it right [associative](https://github.com/purescript/documentation/blob/master/language/Syntax.md#associativity) using `infixr`:
625625

626626
```haskell
627627
infixr 5 insertEntry as ++
@@ -630,7 +630,7 @@ infixr 5 insertEntry as ++
630630
This new operator lets us rewrite the above `book4` example as:
631631

632632
```haskell
633-
book6 = john ++ (peggy ++ (ned ++ emptyBook))
633+
book5 = john ++ (peggy ++ (ned ++ emptyBook))
634634
```
635635

636636
and the right associativity of our new `++` operator lets us get rid of the parentheses without changing the meaning:
@@ -639,11 +639,16 @@ and the right associativity of our new `++` operator lets us get rid of the pare
639639
book6 = john ++ peggy ++ ned ++ emptyBook
640640
```
641641

642-
Likewise, in the code for `findEntry` above, we used a different form of function application: the `head` function was applied to the expression `filter filterEntry book` by using the infix `$` symbol.
642+
Another common technique for eliminating parens is to use `apply`'s infix operator `$`, along with your standard prefix functions.
643+
644+
For example, the earlier `book3` example could be rewritten as:
645+
```haskell
646+
book7 = insertEntry john $ insertEntry peggy $ insertEntry ned emptyBook
647+
```
643648

644-
This is equivalent to the usual application `head (filter filterEntry book)`
649+
Substituting `$` for parens is usually easier to type and (arguably) easier to read. A mnemonic to remember the meaning of this symbol is to think of the dollar sign as being drawn from two parens that are also being crossed-out, suggesting the parens are now unnecessary.
645650

646-
`($)` is just an alias for a regular function called `apply`, which is defined in the Prelude. It is defined as follows:
651+
Note that `$` isn't special syntax that's hardcoded into the language. It's simply the infix operator for a regular function called `apply`, which is defined in the Prelude as follows:
647652

648653
```haskell
649654
apply :: forall a b. (a -> b) -> a -> b
@@ -652,23 +657,15 @@ apply f x = f x
652657
infixr 0 apply as $
653658
```
654659

655-
So `apply` takes a function and a value and applies the function to the value. The `infixr` keyword is used to define `($)` as an alias for `apply`.
656-
657-
But why would we want to use `$` instead of regular function application? The reason is that `$` is a right-associative (`infixr`), low precedence (`0`) operator. This means that `$` allows us to remove sets of parentheses for deeply-nested applications.
658-
659-
For example, the above nested function application to create an `AddressBook` with three entries:
660+
The `apply` function takes another function (of type `(a -> b)`) as its first argument and a value (of type `a`) as its second argument, then calls that function with that value. If it seems like this function doesn't contribute anything meaningful, you are absolutely correct! Your program is logically identical without it (see [referential transparency](https://en.wikipedia.org/wiki/Referential_transparency)). The syntactic utility of this function comes from the special properties assigned to its infix operator. `$` is a right-associative (`infixr`), low precedence (`0`) operator, which lets us remove sets of parentheses for deeply-nested applications.
660661

662+
Another parens-busting opportunity for the `$` operator is in our earlier `findEntry` function:
661663
```haskell
662-
book3 = insertEntry john (insertEntry peggy (insertEntry ned emptyBook))
663-
```
664-
665-
becomes (arguably) easier to read when expressed using `$`:
666-
667-
```haskell
668-
book6 = insertEntry john $ insertEntry peggy $ insertEntry ned emptyBook
664+
findEntry firstName lastName book = head $ filter filterEntry book
669665
```
666+
We'll see an even more elegant way to rewrite this line with "function composition" in the next section.
670667

671-
Wrapping an infix operator in parentheses lets you use it as a prefix function:
668+
If you'd like to use a concise infix operator alias as a prefix function, you can surround it in parenthesis:
672669

673670
```text
674671
> 8 + 3
@@ -678,22 +675,25 @@ Wrapping an infix operator in parentheses lets you use it as a prefix function:
678675
11
679676
```
680677

681-
Alternatively, operators can be partially applied by surrounding them with parentheses and using `_` as an operand in an [operator section](https://github.com/purescript/documentation/blob/master/language/Syntax.md#operator-sections):
678+
Alternatively, operators can be partially applied by surrounding the expression with parentheses and using `_` as an operand in an [operator section](https://github.com/purescript/documentation/blob/master/language/Syntax.md#operator-sections). You can think of this as a more convenient way to create simple anonymous functions (although in the below example, we're then binding that anonymous function to a name, so it's not so anonymous anymore):
682679

683680
```text
684681
> add3 = (3 + _)
685682
> add3 2
686683
5
687684
```
688685

689-
To summarize, the following are equivalent definitions of a function that adds `5` to its argument:
686+
To summarize, the following are equivalent definitions of a function that adds `5` to its argument:
690687

691688
```haskell
692689
add5 x = 5 + x
693690
add5 x = add 5 x
694691
add5 x = (+) 5 x
695692
add5 x = 5 `add` x
696693
add5 = add 5
694+
add5 = \x -> 5 + x
695+
add5 = (5 + _)
696+
add5 x = 5 `(+)` x -- Yo Dawg, I herd you like infix, so we put infix in your infix!
697697
```
698698

699699
## Function Composition
@@ -749,3 +749,4 @@ In this chapter, we covered several new functional programming concepts:
749749
- Using techniques like eta conversion and function composition to refactor code into a clear specification.
750750

751751
In the following chapters, we'll build on these ideas.
752+

0 commit comments

Comments
 (0)