
Algebraic Patterns – Monoid Morphism - alipang
http://philipnilsson.github.io/Badness10k/posts/2016-08-10-functional-patterns-monoid-morphism.html
======
rawnlq
The counting zeroes in "100!" problem is actually a common high school level
math contest problem. You're supposed to calculate it by hand, not with code.
The trick was to notice

\- number of trailing zeros is equal to times you can divide something by 10

\- There are a lot more 2s than 5s as the divisor, so number of 5s is the
limiting factor

\- 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95,
100 contribute (at least) a factor of 5 each

\- 25, 50, 75, 100 contribute another factor of 5 each

So answer is 20 + 4 zeros.

I love monoids but I personally thought that was a bad example. Not only did
it complicate the problem, it didn't actually lead to any understanding that
will let you write a generic and efficient solution for "n!". Something like
this O(log(n)):

    
    
        def countZeroes(n):
          count = 0
          divisor = 5
          while divisor <= n:
            count += n / divisor
            divisor *= 5
          return count
    
        print countZeroes(100)

~~~
alipang
Your solution still assumes we can break down the problem according to the
fundamental theorem of arithmetic, which is a monoid homomorphism. You simply
have added more insight into the problem than I.

The goal of the article is show there's a consistent structural framework of
problem solving underneath. I mention briefly that you can improve the
solution along your lines.

The idea that let's us prove your algorithm above correct using this theory is
that monoid morphisms compose (they form a functor category), and that
equivalence relations that respect monoid composition induces monoid morphisms
to the quotient classes.

Then we just define the equivalnce relation where two numbers are equal if
they have the same number of fives in their prime factorization. The composite
monoid morphism yields your algorithm.

I didn't want to overcomplicate the article with this, but I did mention it
(it's in the hard-to-parse paragraph at the end of the section)

~~~
lomnakkus
This comment is the most amazingly "smug"[1] genuinely apologetic comment I've
ever read. It's just amazing... and informative!

A heartfelt +1 from me! :)

[1] I don't really mean that in a negative way, but it's like Alan Davies and
Stephen Fry on QI, if you know what I mean.

EDIT: I realize that we're not on AGT/BGT or something, but you really should
add a footnote about this.

------
raphlinus
I use monoid homomorphisms extensively in xi-editor, and have a couple of
slides on it at my RustConf talk earlier this month. I hope to be writing up
the ideas in more detail soon (both what I've implemented, and speculative
explorations such as doing incremental syntax highlighting).

~~~
patrec
Sounds interesting -- do you have a link to the slides or relevant part of
your talk?

------
conistonwater
I don't fully understand how category theory terms are helpful in programming.
It always feels backwards to me, that first you write the code, then you look
through the code and pick out all the places where category-theory terminology
might appear. Monoids are nice and all, but in the end it's just a name given
to a specific design pattern: you may as well reason about it in terms of
code.

~~~
danidiaz
Sometimes, wondering if your type is an example of some particular abstraction
can reveal unexpected useful operations, when you fill in the gaps.

For example, there's a Haskell library that defines a type called "Fold a b"
[1]. It's basically a little state machine which you feed values of type "a"
until you close it and then it returns an output of type "b".

Turns out these Folds are examples of an abstraction called a "Comonad". This
basically means that there is a function

> extract:: Fold a b -> b

That runs a fold without giving it any input, and a function

> duplicate :: Fold a b -> Fold a (Fold a b)

That turns a Fold that takes as and returns b into a Fold that takes as and
returns another Fold that takes as and returns b. But what on earth could this
be useful for?

Turns out that "duplicate" lets you keep a Fold "open" when you pass it to
functions that run the Fold and only return its result (say, a function that
feeds the Fold with values read from a file). If you pass a "duplicated Fold"
to such functions, you will get another Fold as result that you can keep
feeding.

The Applicative instance is even more useful: it lets you combine two Folds
into one so that their results can be calculated in a single run.

This kind of useful discovery doesn't always happen, though. Sometimes the new
functions turn out to be useless, or too inefficient.

[1]
[http://hackage.haskell.org/package/foldl-1.2.1/docs/Control-...](http://hackage.haskell.org/package/foldl-1.2.1/docs/Control-
Foldl.html#t:Fold)

~~~
conistonwater
I, for one, think that Fold's documentation can be seriously improved by
describing its behaviour in terms of code, rather than category theory. All
I'm saying is that when even _you_ describe a Fold, you do so in terms of non-
category-theory terms, and that nothing is added by category theory itself.
This is much the same way lenses have some kind of category-theoretic
interpretation, but exactly the same level of understanding can be achieved by
thinking about them in terms of code. And if there's no difference, that means
category theory is essentially unnecessary.

I also want to say that I don't believe Fold was discovered from category
theory, it seems to me more like a neat generalization of foldl, and then once
they had an idea, they asked questions like "is this a comonad?". Indeed, it's
far easier to me to figure out what's going on by reading
[http://hackage.haskell.org/package/foldl-1.2.1/docs/src/Cont...](http://hackage.haskell.org/package/foldl-1.2.1/docs/src/Control-
Foldl.html) to see the Applicative instance itself.

~~~
lomnakkus
Honestly, it just requires a certain familiarity with the general concepts.
Once it's internalized you'll often be thinking in terms of the abstractions
themselves. E.g. "If I can make my <domain-object-X> into a <Monoid/whatever>,
I can apply <all-these-laws>!" type thing. For a concrete example, I've been
doing this in an (unreleased) game to just regularize all the special cases of
"effects" (poison, slowness, etc.) affecting the player. Bundling it all up
into an Effect data type and defining a Monoid for it means that I don't have
to care _at all_ when or how they get applied, whether they have a timer, etc.

> and that nothing is added by category theory itself

In _some_ sense you're right. CT is really just a _systematic_ way of
describing patterns. Theoretically we could just prove loads of special cases
and never have to resort to CT to prove anything... but it sure helps when you
can just invoke the Yoneda Lemma for some special case that you're working
with rather than going through the whole process of re-proving the Yoneda
Lemma for the umteenth time.

(Btw, this isn't specific to CT. It's just that _math_ -level
specification/proof basically always tends towards generalization... for
_really_ good reasons.)

EDIT: I should say that I'm not yet _close_ to the level where I can say that
a "Monad is just a monoid in the category of endofunctors". I'm still just a
muggle in this whole CT thing and yet it's even helping me!

------
Koshkin
Ah... Monoids-shmonoids. While I appreciate abstract algebra, I feel that
forcing it onto students of programming is a terrible idea. An entire
generation of potential engineers and scientists (and even mathematicians) was
lost when they started teaching children that geometric figures can only be
"congruent" to each other, not "equal". In the same way, I would have never
been able to use, say, generic lists without giving this idea a second thought
if they had told me first that those are an example of an important kind of
"endofunctor in the category of types" (i.e. a monad).

------
jiehong
Hi,

I'm new here :)

Each time I see something like that, I think it looks great, but I'm having a
hard time understanding the meaning of the vocabulary used…

Is there any good (free?) resources out there to learn Monoids, Monads,
traits, category theory, in short, anything used in functional languages?

This is something that clearly stops me from using functional languages more.

~~~
icen
There are a million monad tutorials for Haskell (and, with respect to their
use in Haskell, it's probably better to learn them from there). I think that a
good one is "You Could Have Invented Monads!".

This[1] is a good paper about monads in functional programming. It reads quite
similarly to a monad tutorial, but with a little more formality.

As for actual category theory, I've enjoyed the first few chapters of
"Algebra: Chapter 0", by Aluffi.

If you're after more type theory, the usual recommendations are "Types and
Programming Languages", by Pierce, and "Software Foundations", also by Pierce.

[1]
[http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/ba...](http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf)

