Hello @genkami!

First of all thank you for this nice project. I've recently discovered it and find it interesting.

I wanted to send you a letter, but then thought, that this issue maybe useful to some other enthusiasts, and also I can use the markdown formatting. Apologies for a long read and for the fact that I haven't had the chance to push the project to GitHub yet.

Before the generics were available I was playing around Monoids in Golang. My favourite example is FizzBuzz!

So I implemented the solution which was highly inspired by a couple of articles mentioned bellow.
The first approach looked something like this:

```
// FizzBuzzFunctional
//
// https://web.archive.org/web/20130511210903/http://dave.fayr.am/posts/2012-10-4-finding-fizzbuzz.html
// https://medium.com/@iopguy/fizzbuzz-can-finally-be-implemented-in-stable-rust-87649a882f2d
// https://www.parsonsmatt.org/2016/02/27/an_elegant_fizzbuzz.html
func FizzBuzzFunctional(n int) string {
m := monoid.ForString("").
Append(monoid.ForString("Fizz").Filtered(func() bool {
return n%3 == 0
})).
Append(monoid.ForString("Buzz").Filtered(func() bool {
return n%5 == 0
}))
return m.UnwrapOr(strconv.Itoa(n))
}
```

I had to implement an `Optional`

type (an equivalent of Maybe, the name seemed more conventional for Golang). `UnwrapOr`

is basically `FromMaybe`

in Haskell. After that I turned that `Optional`

into a monoid. The API is not ideal, but the solution looks pretty simple. Given that we don't have the monadic list comprehensions I used `Filtered`

function to add the predicated. So basically the structure that implemented the monoid, also had a `Filtered`

method. Not very elegant, but better than nothing.

The beauty of this solution is that we can easily add more predicates: Fizz, Buzz, Bizz, etc... However in order for it to work we need to be able to create a Monoid which is basically a function, and not a concrete a simple type.

My `Optional Monoid`

looked like this:

```
package monoid
type OptionString struct {
op option.String
}
// SomeString wraps the s into an optional string.
func SomeString(s string) OptionString {
return OptionString{
op: option.SomeString(s),
}
}
// NoneString returns an empty optional string.
func NoneString() OptionString {
return OptionString{
op: option.NoneString(),
}
}
func (m OptionString) Empty() OptionString {
return NoneString()
}
func (m OptionString) Append(other OptionString) OptionString {
switch {
case m == NoneString():
return other
case other == NoneString():
return m
default:
return SomeString(m.op.Append(other.op).UnwrapOrDefault())
}
}
func (m OptionString) Filtered(fn func() bool) OptionString {
if fn() {
return m
}
return NoneString()
}
func (m OptionString) UnwrapOr(s string) string {
return m.op.UnwrapOr(s)
}
```

It was using a String Option which supported the Append for convenience, however it was not a Monoid, it didn't respect the Monodic laws, however the monoid.OptionsSting did:

```
func TestOptionString(t *testing.T) {
t.Parallel()
// A set S equipped with a binary operation S × S → S,
// which we will denote •, is a monoid if it satisfies the following two axioms:
t.Run("it has valid identity", func(t *testing.T) {
t.Parallel()
m := monoid.SomeString("test")
// There exists an element e in S such that for every element a in S,
// the equations e • a = a and a • e = a hold.
AssertEqual(t, m, m.Append(m.Empty()))
AssertEqual(t, m.Empty().Append(m), m.Append(m.Empty()))
})
t.Run("it has valid associativity", func(t *testing.T) {
t.Parallel()
a := monoid.SomeString("foo")
b := monoid.SomeString("bar")
c := monoid.NoneString()
// For all a, b and c in S, the equation (a • b) • c = a • (b • c) holds.
AssertEqual(t, a.Append(b).Append(c), a.Append(b.Append(c)))
})
}
```

The new iteration was changed a little to use foldable:

```
func FizzBuzzFunctional(n int) string {
fizz := func(n int) bool {
return n%3 == 0
}
buzz := func(n int) bool {
return n%5 == 0
}
filters := foldable.RuleFoldable{
monoid.ForFizzBuzzPredicate(fizz, "Fizz"),
monoid.ForFizzBuzzPredicate(buzz, "Buzz"),
}
rules := fold(filters, monoid.NewEmptyFizzBuzzRuleset()) // a monoid which combines all the filters together
return monoid.FromStringOption(strconv.Itoa(n), rules(n))
}
// fold :: (Foldable t, Monoid m) => t m -> m
func fold(filters foldable.RuleFoldable, m monoid.FizzBuzzRuleset) monoid.FizzBuzzRuleset {
rules := filters.Foldl(filters.Init(), func(result foldable.T, next foldable.T) foldable.T {
rule, ok := next.(func(int) monoid.OptionString)
mustOk(ok, "cannot cast result foldable.T to func(int) monoid.OptionString")
m = m.Append(rule)
return m
})
ruleSet, ok := rules.(monoid.FizzBuzzRuleset)
mustOk(ok, "cannot cast result foldable.T to monoid.FizzBuzzRuleset")
return ruleSet
}
func mustOk(ok bool, msg string) {
if !ok {
panic(msg)
}
}
```

Now that we have the generics, and your library we probably can come up with a better solution. I tried to use some of your ideas but at the moment you're changing the API faster than I have the time to follow :-D Nonetheless, I was almost able to implement the monoids I need from your wonderful library, however I stuck at the moment with a monoid to combine two functions. It got pretty ugly on my side.

Could you please add an `ExampleTest`

for this `FizzBuzz`

case to demonstrate the usage of your library the way you were intended? What I really would like to achieve is the following translated into Go without being too ugly :)

```
{-# LANGUAGE MonadComprehensions #-}
module Main where
import Data.Monoid (mappend)
import Data.Maybe (fromMaybe, listToMaybe, maybe)
import System.Environment (getArgs)
fizzbuzz i = fromMaybe (show i) $ mappend ["fizz" | i `rem` 3 == 0]
["buzz" | i `rem` 5 == 0]
main = mapM_ putStrLn [ fizzbuzz i | i <- [1..100] ]
```

Thank you very much.