9
votes

The following does not work, for obvious reasons.

(defprotocol Monoid
  (mappend [a b])
  (mzero []))

mzero has zero arguments, and zero argument methods are not allowed (or do not make sense) in protocols. In Haskell or Scala, where the dispatch is type-based rather than value-based, this is not a problem.

What would be the correct way to conceptualize and write Monoid protocol in Clojure?

1
why do you need it to be a protocol rather than a module? if you are expecting different implementations then how would haskell infer which implementation is required in a particular use case? (i think it's a good question, i'm just trying to chase down the issue involved). - andrew cooke
@andrewcooke Haskell infers based on the static type at the use site. The method that is called is resolved statically. - Don Stewart
@andrewcooke, what would module mean in the context of your statement? - missingfaktor
@missingfaktor - what i said was wrong. what i should have said is that mappend would be in the protocol, but the equivalent of mzero would be a function that creates an implementation of that protocol (and lives in a namespace - module - with the implementation). what i am missing, from the above, is how something like mzero can be implied by context separately from a particular implementation. - andrew cooke
@andrewcooke, this example might help to understand how this works in Haskell: ideone.com/j1nnz. - missingfaktor

1 Answers

5
votes

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.