## Monadic List Functions

Here’s an old Haskell chestnut:

```
>>> filterM (\_ -> [False, True]) [1,2,3]
3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]] [[],[
```

`filterM (\_ -> [False,True])`

gives the power set of some input list. It’s one of the especially magical demonstrations of monads. From a high-level perspective, it makes sense: for each element in the list, we want it to be present in one output, and not present in another. It’s hard to see how it actually *works*, though. The (old^{1}) source for `filterM`

doesn’t help hugely, either:

```
filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
= return []
filterM _ [] :xs) = do
filterM p (x<- p x
flg <- filterM p xs
ys return (if flg then x:ys else ys)
```

Again, elegant and beautiful (aside from the three-space indent), but opaque. Despite not really getting how it works, I was encouraged by its simplicity to try my hand at some of the other functions from Data.List.

## Grouping

Let’s start with the subject of my last post. Here’s the implementation:

```
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
= build (\c n ->
groupBy p xs let f x a q
| q x = (x : ys, zs)
| otherwise = ([], c (x : ys) zs)
where (ys,zs) = a (p x)
in snd (foldr f (const ([], n)) xs (const False)))
```

It translates over pretty readily:

```
groupByM :: Applicative m => (a -> a -> m Bool) -> [a] -> m [[a]]
=
groupByM p xs fmap snd (foldr f (const (pure ([], []))) xs (const (pure (False))))
where
= liftA2 st (q x) (a (p x)) where
f x a q
st b (ys,zs)| b = (x : ys, zs)
| otherwise = ([], (x:ys):zs)
```

Let’s try it with a similar example to `filterM`

:

```
>>> groupByM (\_ _ -> [False, True]) [1,2,3]
1],[2],[3]],[[1],[2,3]],[[1,2],[3]],[[1,2,3]]] [[[
```

It gives the partitions of the list!

## Sorting

So these monadic generalisations have been discovered before, several times over. There’s even a package with monadic versions of the functions in Data.List. Exploring this idea with a little more formality is the paper “All Sorts of Permutations” (Christiansen, Danilenko, and Dylus 2016), and accompanying presentation on YouTube. They show that the monadic version of sort produces permutations of the input list, and examine the output from different sorting algorithms. Here’s a couple of their implementations, altered slightly:

```
insertM :: Monad m => (a -> a -> m Bool) -> a -> [a] -> m [a]
= pure [x]
insertM _ x [] @(y:ys) = do
insertM p x yys<- p x y
lte if lte
then pure (x:yys)
else fmap (y:) (insertM p x ys)
insertSortM :: Monad m => (a -> a -> m Bool) -> [a] -> m [a]
= foldrM (insertM p) []
insertSortM p
partitionM :: Applicative m => (a -> m Bool) -> [a] -> m ([a],[a])
= foldr f (pure ([],[])) where
partitionM p = liftA2 ifStmt (p x) where
f x
ifStmt flg (tr,fl)| flg = (x:tr,fl)
| otherwise = (tr,x:fl)
quickSortM :: Monad m => (a -> a -> m Bool) -> [a] -> m [a]
= pure []
quickSortM p [] :xs) = do
quickSortM p (x<- partitionM (p x) xs
(gt,le) <- quickSortM p le
ls <- quickSortM p gt
gs pure (ls ++ [x] ++ gs)
>>> insertSortM (\_ _ -> [False,True]) [1,2,3]
1,2,3],[1,3,2],[3,1,2],[2,1,3],[2,3,1],[3,2,1]]
[[
>>> quickSortM (\_ _ -> [False,True]) [1,2,3]
3,2,1],[2,3,1],[2,1,3],[3,1,2],[1,3,2],[1,2,3]] [[
```

As it should be easy to see, they’re very concise and elegant, and strongly resemble the pure versions of the algorithms.

## State

So the examples above are very interesting and cool, but they don’t necessarily have a place in real Haskell code. If you wanted to find the permutations, partitions, or power set of a list you’d probably use a more standard implementation. That’s not to say that these monadic functions have no uses, though: especially when coupled with `State`

they yield readable and fast implementations for certain tricky functions. `ordNub`

, for instance:

```
ordNub :: Ord a => [a] -> [a]
=
ordNub flip evalState Set.empty .
filterM-> do
(\x <- gets (Set.notMember x)
flg
when flg (modify (Set.insert x))pure flg)
```

Alternatively, using a monadic version of `maximumOn`

:

```
maximumOnM :: (Applicative m, Ord b) => (a -> m b) -> [a] -> m (Maybe a)
= (fmap . fmap) snd . foldl f (pure Nothing)
maximumOnM p where
= liftA2 g a (p e)
f a e where
Nothing q = Just (q, e)
g @(Just (o, y)) q
g b| o < q = Just (q, e)
| otherwise = b
```

You can write a one-pass `mostFrequent`

:

```
mostFrequent :: Ord a => [a] -> Maybe a
=
mostFrequent flip evalState Map.empty .
maximumOnM-> maybe 1 succ <$> state (Map.insertLookupWithKey (const (+)) x 1)) (\x
```

## Decision Trees

One of the nicest things about the paper was the diagrams of decision trees provided for each sorting algorithm. I couldn’t find a library to do that for me, so I had a go at producing my own. First, we’ll need a data type to represent the tree itself:

```
data DecTree t a
= Pure a
| Choice t (DecTree t a) (DecTree t a)
deriving Functor
```

We’ll say the left branch is “true” and the right “false”. Applicative and monad instances are relatively mechanical^{2}:

```
instance Applicative (DecTree t) where
pure = Pure
Pure f <*> xs = fmap f xs
Choice c ls rs <*> xs = Choice c (ls <*> xs) (rs <*> xs)
instance Monad (DecTree t) where
Pure x >>= f = f x
Choice c ls rs >>= f = Choice c (ls >>= f) (rs >>= f)
```

We can now create a comparator function that constructs one of these trees, and remembers the values it was given:

```
traceCompare :: a -> a -> DecTree (a,a) Bool
= Choice (x,y) (Pure True) (Pure False) traceCompare x y
```

Finally, to draw the tree, I’ll use a function from my binary tree library:

```
printDecTree :: (Show a, Show b) => String -> DecTree (a,a) b -> IO ()
= putStr (drawTreeWith id (go t) "") where
printDecTree rel t Pure xs) = Node (show xs) Leaf Leaf
go (Choice (x,y) tr fl) =
go (Node (show x ++ rel ++ show y) (go tr) (go fl)
```

And we get these really nice diagrams out:

```
>>> (printDecTree "<=" . insertSortM traceCompare) [1,2,3]
1,2,3]
┌[1<=2┤
┌2,1,3]
│ │ ┌[1<=3┤
│ └2,3,1]
│ └[2<=3┤
1,3,2]
│ ┌[1<=3┤
└3,1,2]
│ ┌[1<=2┤
└3,2,1]
└[
>>> (printDecTree "<=" . quickSortM traceCompare) [1,2,3]
1,2,3]
┌[2<=3┤
┌1,3,2]
│ └[1<=3┤
┌3,1,2]
│ └[1<=2┤
2,1,3]
│ ┌[1<=3┤
└2,3,1]
│ ┌[2<=3┤
└3,2,1] └[
```

We can also try it out with the other monadic list functions:

```
>>> (printDecTree "=" . groupByM traceCompare) [1,2,3]
1,2,3]]
┌[[2=3┤
┌1,2],[3]]
│ └[[1=2┤
1],[2,3]]
│ ┌[[2=3┤
└1],[2],[3]] └[[
```

## Applicative

You might notice that none of these “monadic” functions actually require a monad constraint: they’re all applicative. There’s a straightforward implementation that relies only on applicative for most of these functions, with a notable exception: sort. Getting *that* to work with just applicative is the subject of a future post.

### References

Christiansen, Jan, Nikita Danilenko, and Sandra Dylus. 2016. “All Sorts of Permutations (Functional Pearl).” In *Proceedings of the 21st ACM SIGPLAN International Conference on Functional Programming*, 168–179. ICFP 2016. New York, NY, USA: ACM. doi:10.1145/2951913.2951949. http://informatik.uni-kiel.de/~sad/icfp2016-preprint.pdf.

The definition has since been updated to more modern Haskell: it now uses a fold, and only requires

`Applicative`

.↩︎Part of the reason the instances are so mechanical is that this type strongly resembles the free monad:

`data Free f a = Pure a | Free (f (Free f a))`

In fact, the example given in the

`MonadFree`

class is the following:`data Pair a = Pair a a`

`type Tree = Free Pair`

The only difference with the above type and the decision tree is that the decision tree carries a tag with it.

So what’s so interesting about this relationship? Well,

`Pair`

is actually a representable functor. Any representable functor`f a`

can be converted to (and from) a function`key -> a`

, where`key`

is the specific key for`f`

. The key for`Pair`

is`Bool`

: the result of the function we passed in to the sorting functions!In general, you can make a “decision tree” for any function of type

`a -> b`

like so:`type DecTree a b r = Rep f ~ b => Free (Compose ((,) a) f) r`

But more on that in a later post.↩︎