Cookies help us analyse how or Website is being used, provide you a better experience and serve most relevant content. FunctionalWorks

# You Can Unfold So Much More with Monoid: Examples

Marty Stumpf

7 Apr 2022 • Functional Programming
• Typed Functional Programming

This is the eighth of a series of articles that illustrates functional programming (FP) concepts. As you go through these articles with code examples in Haskell (a very popular FP language), you gain the grounding for picking up any FP language quickly. Why should you care about FP? See this post.

In the last post, we wrote an `unfold` function that works for the `Monoid` type class. In this post we'll look at some examples of applying our `unfold` to other type instances of `Monoid`.

## Unfolding a List

### With Haskell's `unfoldr`

Recall Haskell's default `unfold` with this signature:

``````unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
``````

Note that this unfold takes an initial input. We saw an example of its usage:

``````example :: (Ord a, Num a) => a -> [a]
example = unfoldr (\x -> if x > 9 then Nothing else Just (x, x+1))
``````

`example 7` returns:

``````[7,8,9]
``````

### With Our Monoid `unfoldm`

Our unfold is more general which means we can unfold to a list using it, like Haskell's default unfold. Recall our unfold's type signature:

``````unfoldm :: Monoid m => (t -> Maybe (m, t)) -> t -> m
``````

Note that the `Maybe` returns a tuple with its first element of a type that belongs to the `Monoid` type class. When we use our `unfoldm`, we need to make sure of that. To apply `unfoldm` in a manner similar to the above example, we have to return `[x]` not just `x` in the `else` case:

``````example =
unfoldm (\x -> if x > 9 then Nothing else Just ([x], x+1))
``````

Running `example 7` returns the same result as above.

## Unfolding to Other Monoid Types

Now, let's unfold to other `Monoid` types!

### Unfolding to `Map`

Haskell has a `Map` data type. As mentioned in its reference:

``````data Map k a

A Map from keys k to values a.

Instance
Ord k => Monoid (Map k v)
``````

`Map` is a data type that maps keys to their values, similar to a dictionary. When you look up a key (or a word in the case of a dictionary), you get its associated value (or in the case of a dictionary, the meaning of the word).

`Map` belongs to the `Monoid` type class if the key `k` is orderable . This means that if the key is orderable, we can use our unfold function to unfold to a `Map`!

Here is an example of a unfolding a `Map` with `keys` that are of a type such that `k > 26` is valid:

``````import Data.Map as Map

-- our unfoldm from the last post
unfoldm :: Monoid m => (t -> Maybe (m, t)) -> t -> m
unfoldm f a =
case f a of
Just (first, second) ->
first `mappend` (unfoldm f second)
Nothing -> mempty

mapExample :: (Ord k, Num k, Enum v) => (k, v) -> Map.Map k v
mapExample =
unfoldm
(\(x,y) ->
if x > 26 then Nothing
else Just ((Map.insert x y empty),((x+1),(succ y))))
``````

Because the type of the keys also belongs to the `Ord` typeclass, this `Map` belongs to the `Monoid` typeclass. Therefore, we can use our `unfoldm` function with it.

I have specified the `value` is of a type that belongs to the `Enum` typeclass. This allows me to use the `succ` (successor) function.

The function we input to our `unfoldm` takes a `tuple`. The first element of the `tuple` is the `key`, while the second element is the `value`.

The unfolding stops when the `key` is greater than 26. We start with the input `key` and `value`, then we `mappend` (or `insert` in this case with `Map`) with the `key` goes up by 1 and the `value` being the successor of the current value each time.

Running `mapExample` with the integer 1 and the `Char` `K`, or `(1,'K')` gives:

``````*Main> mapExample (1,'K')
fromList [(1,'K'),(2,'L'),(3,'M'),(4,'N'),(5,'O'),(6,'P'),(7,'Q'),(8,'R'),(9,'S'),(10,'T'),(11,'U'),(12,'V'),(13,'W'),(14,'X'),(15,'Y'),(16,'Z'),(17,'['),(18,'\\'),(19,']'),(20,'^'),(21,'_'),(22,'`'),(23,'a'),(24,'b'),(25,'c'),(26,'d')]
``````

Running it with the `value` of type `Float` works too, because it belongs to the `Enum` class:

``````*Main> mapExample (0,1.55)
fromList [(0,1.55),(1,2.55),(2,3.55),(3,4.55),(4,5.55),(5,6.55),(6,7.55),(7,8.55),(8,9.55),(9,10.55),(10,11.55),(11,12.55),(12,13.55),(13,14.55),(14,15.55),(15,16.55),(16,17.55),(17,18.55),(18,19.55),(19,20.55),(20,21.55),(21,22.55),(22,23.55),(23,24.55),(24,25.55),(25,26.55),(26,27.55)]
``````

Because the output of `mapExample` is a `Map`, we can apply `Map`'s method on it, for example, we can look up the value of a specific key using `lookup`:

``````*Main> Map.lookup 10 (mapExample (1,'K'))
Just 'T'
``````

### Unfolding to `Set`

The `Set e` type represents a set of elements of type `e`. If `e` is an orderable type then the `Set e` type belongs to the `Monoid` typeclass.

I challenge you to write a function that unfolds to a `Set` using `unfoldm`. Have fun!

As you can see, once we master some functional programming concepts, we can apply them in any way we want to great effect! With the concept of unfold and the Monoid type class, we built a more powerful unfold function. This is what I love about functional programming: it's so powerful!

In a later post, I will explain the concept of list being a free `Monoid` - it will shed light on why `Map` can be generated by a `fromList` function above.

Marty Stumpf

Software engineer. Loves FP Haskell Coq Agda PLT. Always learning. Prior: Economist. Vegan, WOC in solidarity with POC.

See other articles by Marty

Related jobs

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works hello@works-hub.com Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ 108 E 16th Street, New York, NY 10003