First and foremost, this post is inspired by this post. You will want to read this post, as it’s insightful, short and explains the code that I’m about to borrow. I noticed an interesting thing while reading that post, so I figured I’d make a post here in PureScriptland.

In Mark’s post, he goes on to construct a solution to the fizz buzz question with just the `Maybe`

`Monoid`

.
A full `Monoid`

is needed for two reasons:

- Haskell doesn’t have a
`Semigroup`

in the base package `mconcat`

is used, and that needs an identity element. Although, actually, since the list is never empty, it could’ve used something like`sconcat`

from the Semigroups package.

In PureScript, we’ve got a `Semigroup`

in the prelude, and I’m going to do away with `mconcat`

in exchange for `<>`

.

Let’s start by converting the Haskell code to PureScript (with a little abstraction over `fizz`

and `buzz`

).

```
module FizzBuzz where
import Data.Array
import Data.Foldable
import Data.Maybe
import Data.Monoid
import Debug.Trace
fizzBuzz :: Number -> Maybe String
fizzBuzz = mconcat [fizz, buzz]
fizz = ifMod 3 "Fizz"
buzz = ifMod 5 "Buzz"
ifMod :: Number -> String -> Number -> Maybe String
ifMod m str n = if n % m == 0 then Just str else Nothing
main = traverse_ (print <<< go) $ range 1 100
where go n = maybe (show n) id (fizzBuzz n)
```

With a little help from bower we can run this in node and get the output we expect:

```
$ bower i purescript-{arrays,foldable-traversable,maybe,monoid}
...
$ psc fizzbuzz.purs bower_components/purescript-*/src/**/*.purs --main=FizzBuzz | node
"1"
"2"
"Fizz"
"4"
"Buzz"
"Fizz"
"7"
"8"
"Fizz"
"Buzz"
"11"
"Fizz"
"13"
"14"
"FizzBuzz"
...
```

Wonderful, so we can convert some Haskell into PureScript.
Something we should take note of is the instance for `Semigroup`

on functions.
When I was playing around with this code, I was reminded of `on`

from `Data.Function`

.
Its implementation is:

```
on :: forall a b c. (b -> b -> c) -> (a -> b) -> a -> a -> c
on f g x y = g x `f` g y
```

If we replace the `f`

by `<>`

and allow each side to take their own functions, but use the same input, we see that is exactly the `Semigroup`

instance for functions.
Let’s look at what type this function would have.

```
forall a b c. (b -> b -> c) -> (a -> b) -> (a -> b) -> a -> c
```

Huh, now that looks awfully similar to `lift2`

from `Control.Apply`

(modulo some parens).
Let’s see its implementation:

```
lift2 :: forall a b c f. (Apply f) => (a -> b -> c) -> f a -> f b -> f c
lift2 f a b = f <$> a <*> b
```

So if we could find an instance of `Apply`

that worked for functions, we could just use lift2, or its implemenation.
But there should be an instance of `Apply`

for functions, the instance we just showed in the type signature above.
We just need to sub out the `a`

’s in `lift2`

for `b`

’s and fix the `f`

instance to `(a ->)`

in order to match our wanted type.
We get:

```
lift2' :: forall a b c. (b -> b -> c) -> (a -> b) -> (a -> b) -> (a -> c)
lift2' f a b = f <$> a <*> b
```

Interesting! So we could’ve used `lift2 (<>)`

for our `Semigroup`

implementation.
I always find it interesting to see these concepts that seem so disparate can actually be connected.

The next move should come as no surprise.
We’re going to replace `mconcat`

with an inlined call to `<>`

.

```
fizzBuzz = (<>) <$> fizz <*> buzz
```

This works well because it removes the necessity of a `Monoid`

constraint.
Well, that’s pretty cool.
We managed to sneak in an `Apply`

into fizz buzz and drop a `Monoid`

instead.

The completed program is:

```
module FB where
import Data.Array
import Data.Foldable
import Data.Maybe
import Debug.Trace
fizzBuzz = (<>) <$> fizz <*> buzz
fizz = ifMod 3 "Fizz"
buzz = ifMod 5 "Buzz"
ifMod :: Number -> String -> Number -> Maybe String
ifMod m str n = if n % m == 0 then Just str else Nothing
main = traverse_ (print <<< go) $ range 1 100
where go n = maybe (show n) id (fizzBuzz n)
```

Of course, this change from `mconcat`

to `<>`

changes how we would extend the program.
In Mark’s program, we can extend it by simply adding another function to the list in `fizzBuzz`

.
In this program we have to be a bit more cautious, Since `<>`

is a binary function.
We can extend it with another function:

```
fizzBuzzBazz = (<>) <$> fizzBuzz <*> bazz
```

So we’d have an extended whole program of (increasing the upper bound so we actually hit the composition of `fizz`

, `buzz`

, and `bazz`

):

```
module FB where
import Data.Array
import Data.Foldable
import Data.Maybe
import Debug.Trace
fizzBuzz = (<>) <$> fizz <*> buzz
fizzBuzzBazz = (<>) <$> fizzBuzz <*> bazz
fizz = ifMod 3 "Fizz"
buzz = ifMod 5 "Buzz"
bazz = ifMod 7 "Bazz"
ifMod :: Number -> String -> Number -> Maybe String
ifMod m str n = if n % m == 0 then Just str else Nothing
main = traverse_ (print <<< go) $ range 1 110
where go n = maybe (show n) id (fizzBuzzBazz n)
```

This gets a bit hairy if we need to continue extending it, so it’s probably better to move on to using the `Monoid`

instance as in the original post:

```
module FB where
import Data.Array
import Data.Foldable
import Data.Maybe
import Debug.Trace
fizzBuzzBazz = mconcat [fizz, buzz, bazz]
fizz = ifMod 3 "Fizz"
buzz = ifMod 5 "Buzz"
bazz = ifMod 7 "Bazz"
ifMod :: Number -> String -> Number -> Maybe String
ifMod m str n = if n % m == 0 then Just str else Nothing
main = traverse_ (print <<< go) $ range 1 110
where go n = maybe (show n) id (fizzBuzzBazz n)
```