The following does not work, for obvious reasons.
(defprotocol Monoid
(mappend [a b])
(mzero []))
mzero has zero arguments, an
looking at the source, the way that this is implemented in the new reducers library is not as a procotol but an overloaded function. a no-args call is mzero; two args call is mappend.
more exactly, monoid takes two arguments - op and ctor and returns a function which, when called with no arguments, evaluates ctor, and when called with two, delegates to op.
this is consistent with how zero is handled in a fold, for example - reduce (fold) will evaluate the function being folded with no args to find the zero, if necessary.
i feel a bit ashamed to show something so unexciting, but i don't see how you can do better within clojure. thanks for the explanations/education in the comments.