Update and publish catamorphism article
This commit is contained in:
parent
ded50480a8
commit
57aecc46be
|
@ -99,3 +99,14 @@ invert :: BinaryTree a -> BinaryTree a
|
||||||
invert = cata $ \case
|
invert = cata $ \case
|
||||||
LeafF -> Leaf
|
LeafF -> Leaf
|
||||||
NodeF a l r -> Node a r l
|
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"
|
title: "Generalizing Folds in Haskell"
|
||||||
date: 2022-04-22T12:19:22-07:00
|
date: 2022-04-22T12:19:22-07:00
|
||||||
draft: true
|
|
||||||
tags: ["Haskell"]
|
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 <a href="https://en.wikipedia.org/wiki/Inductive_type">inductive types</a>.
|
||||||
|
{{< /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
|
### Recursive Functions
|
||||||
Let's start off with a little bit of a warmup, and take a look at a simple recursive function:
|
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:
|
`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 >}}
|
{{< 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`?
|
#### What About `Foldable`?
|
||||||
If you've been around the Haskell ecosystem, you may know the `Foldable` type class.
|
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
|
Isn't this exactly what we've been working towards here? No, not at all. Take
|
||||||
|
|
Loading…
Reference in New Issue
Block a user