We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies.

We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies. Less

We use cookies and other tracking technologies... More

Login or register
to publish this job!

Login or register
to save this job!

Login or register
to save interesting jobs!

Login or register
to get access to all your job applications!

Login or register to start contributing with an article!

Login or register
to see more jobs from this company!

Login or register
to boost this post!

Show some love to the author of this blog by giving their post some rocket fuel ๐Ÿš€.

Login or register to search for your ideal job!

Login or register to start working on this issue!

Login or register
to save articles!

Login to see the application

Engineers who find a new job through Functional Works average a 15% increase in salary ๐Ÿš€

You will be redirected back to this page right after signin

Blog hero image

You Can Unfold So Much More with Monoid: Examples

Marty Stumpf 24 August, 2021 | 4 min read

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.

Join our newsletter
Join over 111,000 others and get access to exclusive content, job opportunities and more!

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.

Author's avatar
Marty Stumpf
Software engineer. Loves FP Haskell Coq Agda PLT. Always learning. Prior: Economist. Vegan, WOC in solidarity with POC.

Related Issues

open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Open
  • 0
  • 0
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 1
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Open
  • 0
  • 0
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Open
  • 0
  • 0
  • Intermediate
  • HTML

Get hired!

Sign up now and apply for roles at companies that interest you.

Engineers who find a new job through Functional Works average a 15% increase in salary.

Start with GitHubStart with Stack OverflowStart with Email