Skip to content

Commit

Permalink
[Chapter 5] Use pattern matching (ch4) in ch5 (#465)
Browse files Browse the repository at this point in the history
* chore: use pattern matching (ch4) in ch5

* Remove leftover if/then/else
  • Loading branch information
d-s-d authored Dec 9, 2023
1 parent c584cf0 commit 1f5e18d
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 33 deletions.
36 changes: 11 additions & 25 deletions exercises/chapter5/test/Examples.purs
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,21 @@ import Data.Path (Path, ls)

-- ANCHOR: factorial
factorial :: Int -> Int
factorial n =
if n == 0 then
1
else
n * factorial (n - 1)
factorial 0 = 1
factorial n = n * factorial (n - 1)
-- ANCHOR_END: factorial

-- ANCHOR: fib
fib :: Int -> Int
fib n =
if n == 0 then
0
else if n == 1 then
1
else
fib (n - 1) + fib (n - 2)
fib 0 = 0
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)
-- ANCHOR_END: fib

-- ANCHOR: length
length :: forall a. Array a -> Int
length arr =
if null arr then
0
else
1 + (length $ fromMaybe [] $ tail arr)
length [] = 0
length arr = 1 + (length $ fromMaybe [] $ tail arr)
-- ANCHOR_END: length

-- ANCHOR: factors
Expand Down Expand Up @@ -63,21 +53,17 @@ factorsV3 n = do

-- ANCHOR: factorialTailRec
factorialTailRec :: Int -> Int -> Int
factorialTailRec n acc =
if n == 0
then acc
else factorialTailRec (n - 1) (acc * n)
factorialTailRec 0 acc = acc
factorialTailRec n acc = factorialTailRec (n - 1) (acc * n)
-- ANCHOR_END: factorialTailRec

-- ANCHOR: lengthTailRec
lengthTailRec :: forall a. Array a -> Int
lengthTailRec arr = length' arr 0
where
length' :: Array a -> Int -> Int
length' arr' acc =
if null arr'
then acc
else length' (fromMaybe [] $ tail arr') (acc + 1)
length' [] acc = acc
length' arr' acc = length' (fromMaybe [] $ tail arr') (acc + 1)
-- ANCHOR_END: lengthTailRec

-- ANCHOR: allFiles_signature
Expand Down
10 changes: 2 additions & 8 deletions text/chapter5.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ Here is another common example that computes the _Fibonacci function_:

Again, this problem is solved by considering the solutions to subproblems. In this case, there are two subproblems, corresponding to the expressions `fib (n - 1)` and `fib (n - 2)`. When these two subproblems are solved, we assemble the result by adding the partial results.

> Note that, while the above examples of `factorial` and `fib` work as intended, a more idiomatic implementation would use pattern matching instead of `if`/`then`/`else`. Pattern-matching techniques are discussed in a later chapter.
## Recursion on Arrays

We are not limited to defining recursive functions over the `Int` type! We will see recursive functions defined over a wide array of data types when we cover _pattern matching_ later in the book, but for now, we will restrict ourselves to numbers and arrays.
Expand All @@ -63,7 +61,7 @@ import Data.Maybe (fromMaybe)
{{#include ../exercises/chapter5/test/Examples.purs:length}}
```

In this function, we use an `if .. then .. else` expression to branch based on the emptiness of the array. The `null` function returns `true` on an empty array. Empty arrays have a length of zero, and a non-empty array has a length that is one more than the length of its tail.
In this function, we branch based on the emptiness of the array. The `null` function returns `true` on an empty array. Empty arrays have a length of zero, and a non-empty array has a length that is one more than the length of its tail.

The `tail` function returns a `Maybe` wrapping the given array without its first element. If the array is empty (i.e., it doesn't have a tail), `Nothing` is returned. The `fromMaybe` function takes a default value and a `Maybe` value. If the latter is `Nothing` it returns the default; in the other case, it returns the value wrapped by `Just`.

Expand Down Expand Up @@ -489,11 +487,7 @@ One common way to turn a not tail recursive function into a tail recursive is to
For example, consider again the `length` function presented at the beginning of the chapter:

```haskell
length :: forall a. Array a -> Int
length arr =
if null arr
then 0
else 1 + (length $ fromMaybe [] $ tail arr)
{{#include ../exercises/chapter5/test/Examples.purs:length}}
```

This implementation is not tail recursive, so the generated JavaScript will cause a stack overflow when executed on a large input array. However, we can make it tail recursive, by introducing a second function argument to accumulate the result instead:
Expand Down

0 comments on commit 1f5e18d

Please sign in to comment.