Thatâs an interesting question indeed.
Personally, I like to think of data structures in terms of their âmorally ideal formsâ, and for Set
, that is something like âzero or one instances of each distinct element value; order is not preservedâ. Structure-preserving, then, would mean that for each input element, the output set contains exactly one output element. So if the input set has 6 elements, the output set should also have 6 elements - they can be in any order, but there must be 6 of them, and each must correspond to one of the 6 input elements. That, at least, is my intuition for what fmap
on a Set
should do.
But this is only the case if the fmapped function is injective, otherwise we two different input elements might map to the same output element, so the output set would be smaller than the input set, and âstructureâ would be lost.
Interestingly, though, the usual functor laws do not forbid this - fmap id === id
and fmap (g . f) === fmap f . fmap g
still hold - but for sets, this isnât enough to comply with the intuition of âpreserving structureâ - we can, in fact, do something like fmap (const ())
on any set, and weâll get a singleton set containing just the unit value for any non-empty input set, regardless of whatâs in it, which I would hardly say is âstructure preservingâ in any useful sense.
Then again, maybe other people have different intuitions about what âstructure preservingâ is supposed to mean, in which case the Functor
instance would be fine.