### Update and publish catamorphism article

master
parent ded50480a8
commit 57aecc46be
2 changed files with 49 additions and 1 deletions
1. 11
code/catamorphisms/Cata.hs
2. 39
 `@ -99,3 +99,14 @@ invert :: BinaryTree a -> BinaryTree a` `invert = cata \$ \case` ` LeafF -> Leaf` ` NodeF a l r -> Node a r l` ``` ``` `data MaybeF a b = NothingF | JustF a deriving Functor` ``` ``` `instance Cata (Maybe a) (MaybeF a) where` ` out Nothing = NothingF` ` out (Just x) = JustF x` ``` ``` `getOrDefault :: a -> Maybe a -> a` `getOrDefault d = cata \$ \case` ` NothingF -> d` ` JustF a -> a`
 `@ -1,10 +1,17 @@` `---` `title: "Generalizing Folds in Haskell"` `date: 2022-04-22T12:19:22-07:00` `draft: true` `tags: ["Haskell"]` `---` ``` ``` `Have you encountered Haskell's `foldr` function? Did you know that you can use it to express any ` `function on a list? What's more, there's a way to derive similar functions for` `{{< sidenote "right" "positive-note" "a large class of data types in Haskell." >}}` `Specifically, this is the class of inductive types.` `{{< /sidenote >}}` `This is precisely the focus of this post.` `Before we get into the details, it's good to review the underlying concepts in a more familiar setting: functions.` ``` ``` `### Recursive Functions` `Let's start off with a little bit of a warmup, and take a look at a simple recursive function:` ``length`. Here's a straightforward definition:` `@ -338,6 +345,36 @@ Given this, here's an implementation of that `invert` function we mentioned earl` ``` ``` `{{< codelines "Haskell" "catamorphisms/Cata.hs" 98 101 >}}` ``` ``` `#### Degenerate Cases` ``` ``` `Actually, the data types we consider don't have to be recursive. We can apply the same` `procedure of replacing recursive occurrences in a data type's definition with a new type parameter` `to `Maybe`; the only difference is that now the new parameter will not be used!` ``` ``` `{{< codelines "Haskell" "catamorphisms/Cata.hs" 103 107 >}}` ``` ``` `And then we can define a function on `Maybe` using `cata`:` ``` ``` `{{< codelines "Haskell" "catamorphisms/Cata.hs" 109 112 >}}` ``` ``` `This isn't _really_ useful, since we're still pattern matching on a type that looks` `identical to `Maybe` itself. There is one reason that I bring it up, though. Remember` `how `foldr` was equivalent to `cata` for `MyList`, because defining a function `MyListF a -> a` was` `the same as providing a base case `a` and a "combining function" `Int -> a -> a`? Well,` `defining a function `MaybeF x a -> a` is the same as providing a base case `a` (for `NothingF`)` `and a handler for the contained value, `x -> a`. So we might imagine the `foldr` function for `Maybe`` `to have type:` ``` ``` ````Haskell` `maybeFold :: a -> (x -> a) -> Maybe x -> a` ````` ``` ``` `This is exactly the function [`maybe` from `Data.Maybe`](https://hackage.haskell.org/package/base-4.16.1.0/docs/Data-Maybe.html#v:maybe)! Hopefully you can follow a similar process in your head to arrive at "fold"` `functions for `Either` and `Bool`. Indeed, there are functions that correspond to these data types` `in the Haskell standard library, named [`either`](https://hackage.haskell.org/package/base-4.16.1.0/docs/Data-Either.html#v:either) and [`bool`](https://hackage.haskell.org/package/base-4.16.1.0/docs/Data-Bool.html#v:bool).` `Much like `fold` can be used to represent any function on lists, `maybe`, `either`, and `bool` can be` `used to represent any function on their corresponding data types. I think that's neat.` ``` ``` `#### What About `Foldable`?` `If you've been around the Haskell ecosystem, you may know the `Foldable` type class.` `Isn't this exactly what we've been working towards here? No, not at all. Take`