
On Tue, Apr 30, 2013 at 09:46:01PM -0400, Edward Kmett wrote:
instance Foldable Baz where foldmap f (Baz a) = f a
is an innocent typo that would then just mean that foldMap when applied to Baz will silently loop forever with no warning to the programmer. Traversable Baz behaves similarly with the cyclic between sequenceA+fmap and traverse.
Maybe we need a better answer for the default method cycle problem? I had the following vague idea one day: don't allow default definitions in class members. Just use things along the lines of fmapDefault, or, say, subtractFromPlusNegate :: (n -> n -> n) -> (n -> n) -> n -> n -> n subtractFromPlusNegate (+!) neg a b = a +! neg b A bit clumsier but way more explicit: no more warning-silent infinite loops from code you didn't even write. The only drawback is the lack of the ability to introduce new class methods with default definitions. But! Here's my second idea: use RecordWildcards and NamedFieldPuns, allow pattern bindings instead of just simple variables in class instances, and do something like this: data MonoidInstance m = MkMonInst { mempty :: m , mappend :: m -> m -> m } monoidFromMconcat :: ([m] -> m) -> MonoidInstance m monoidFromMconcat mcat = MkMonInst { mconcat = mcat , mempty = mcat [] , mappend x y = mcat [x,y] } -- possibly slightly silly monoidFromMemptyMappend :: m -> (m -> m -> m) -> MonoidInstance m monoidFromMemptyMappend mempty mappend = MkMonInst {..} where mconcat = foldr mempty mappend instance Monoid [a] where MkMonInst {..} = monoidFromMconcat concat Now if I later wanted to add a new method to Monoid, I could just add a new field to MonoidInstance and have the instance-generator functions produce it from the others. Notice that this also leaves me free to have overlapping minimal complete definitions, which the current system doesn't – I explicitly state which one I am using by my choice of monoidFrom function. Anyway, that's something of a digression. My opinion on the issue at hand is that I'd very much like to see a general form of "declaration-let" that would allow me to declare some things local to a group of bindings. If I understand correctly, this would make the specific proposal at hand redundant, and is useful in other situations as well. -- Ben