(+)
and (++)
are just specializations of mappend
; am I right? Why are they needed? This is useless duplication since Haskell has these powerful typeclasses and type inference.
Let's say we delete (+)
and (++)
and rename mappend
(+)
for visual convenience and typing gain.
Coding would be more intuitive, shorter and more understandable for beginners:
--old and new
1 + 2
--result
3
--old
"Hello" ++ " " ++ "World"
--new
"Hello" + " " + "World"
--result
"Hello World"
--old
Just [1, 2, 3] `mappend` Just [4..6]
--new
Just [1, 2, 3] + Just [4..6]
--result
Just [1, 2, 3, 4, 5, 6]
(It makes me dream.). Three, and maybe more, functions for the same thing isn't a good thing for a beautiful language who insists on abstraction and stuff such as Haskell.
I also saw the same kind of repetitions with monads: fmap
is the same, or nearly, as map
, (.)
, liftM
, mapM
, forM
, ...
I know there are historial reasons for fmap
, but what about monoids? Is the Haskell commitee planning something about this? It would break some codes, but I heard, though I'm not sure, there's an incoming version which will have great changes, which is a great occasion. It's too much a pity... At least, is a fork affordable?
EDIT
In answers I read, there is the fact that for numbers, either (*)
or (+)
could fit in mappend
. In fact, I think that (*)
should be part of Monoid
! Look:
Currently, forgeting about the functions mempty
and mconcat
, we only have mappend
.
class Monoid m where
mappend :: m -> m -> m
But we could do that:
class Monoid m where
mappend :: m -> m -> m
mmultiply :: m -> m -> m
It would (maybe, I haven't though enough about it yet) behave as follows:
3 * 3
mempty + 3 + 3 + 3
0 + 3 + 3 + 3
9
Just 3 * Just 4
Just (3 * 4)
Just (3 + 3 + 3 +3)
Just 12
[1, 2, 3] * [10, 20, 30]
[1 * 10, 2 * 10, 3 * 10, ...]
[10, 20, 30, 20, 40, 60, ...]
Actually 'mmultiply' would just be defined only in terms of 'mappend' so for instances of Monoid
there is no need to redefine it! Then Monoid
is closer to mathematics; maybe we could as well add (-)
and (/)
to the class!
If this works, I think it would solve the case of Sum
and Product
as well as the functions duplication: mappend
becomes (+)
and the new mmultiply
is just (*)
.
Basically I suggest a refactoring of code with a "pull up".
Oh, we would need as well a new mempty
for (*)
.
We could abstract these operators in a class MonoidOperator
and define Monoid
as follows:
class (Monoid m) => MonoidOperator mo m where
mempty :: m
mappend :: m -> m -> m
instance MonoidOperator (+) m where
mempty = 0
mappend = --definition of (+)
instance MonoidOperator (*) where
--...
class Monoid m where
-...
Well I don't know how to do this yet but I think there is a cool solution for all of this.