0

I was going through the laws that govern Monoids and one of the two laws state that the append operation must be associative. For function composition this means that for all functions X->X given there are 3 functions f,g and h (f∘g)∘h=f∘(g∘h)

In scalaz I see that there is a type called EndoMonoid and it uses compose for appends which is different from the way normal function compositions work

val f : Int => Int = x => x*x 
val g : Int => Int = y => y + 1 

val e = f.endo |+| g.endo
val d = g.endo |+| f.endo

e run 10
Int = 121

d run 10
Int = 101

As can be seen from the above results that the functions don't satisfy the associative property. Does this mean that not all functions of type X -> X is a monoid?

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
Jayadeep Jayaraman
  • 2,747
  • 3
  • 15
  • 26

1 Answers1

1

What you claim cannot be seen from your example.

Your example only proves that function composition is not commutative. But function composition never was supposed to be commutative: if it were commutative, all math and programming would catastrophically collapse to counting the number of occurrences of basic operations (that is, if "counting" itself would somehow survive that... I'm not sure whether it's possible).

To demonstrate an example of associativity, you need a third function h: Int => Int, and then you have to compare

 (f.endo |+| g.endo) |+| h.endo

vs.

 f.endo |+| (g.endo |+| h.endo)

exactly as the rule (that you yourself have just quoted!) states.

Every set of endomorphisms is always a monoid, because categories are essentially just "monoids with many objects", whereas monoids are just "categories with a single object". If you take any category and then look at the endomorphisms at a single object, you automatically, by definition, obtain a monoid. That's in particular true for the canonical ambient "category" of ordinary functions. [Here should come the usual disclaimer that it's not really a category, and that in every real programming language nothing is really true]

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • thank you, I got confused with the placing of brackets. Typically the brackets signify the order in which things are evaluated. I thought that in the case of `f.endo |+| (g.endo |+| h.endo)` the functions inside the bracket are evaulated first therefore in the above case it would be `f(g(h(x))` vs `(f.endo |+| g.endo ) |+| h.endo` where it would have been evaluated as `h(f(g(x)))`, but I believe now that the bracket has no significance as the `append` rule for function is f compose g compose h irrespective of where the brackets are placed. Please advice. – Jayadeep Jayaraman Apr 03 '18 at 02:34
  • @jjayadeep The brackets say nothing at all about evaluation. They only enforce operator precedence. Whether the stuff in brackets is evaluated at all is a separate question. For example, if you evaluate `true || (true && {println("Hey!"); true})`, then the stuff in brackets is not evaluated at all. In your question, `f o (g o h)` means that `g` and `h` are composed first, and then `f` is composed with `(g o h)`. Likewise, `(f o g) o h` means: `f` and `g` are composed first, then `(f o g)` is composed with `h`. Associativity means: these two things are essentially the same. – Andrey Tyukin Apr 03 '18 at 02:45