# Difference between revisions of "Type classes are for reusability"

(good and bad examples of type class use) |
(corrections) |
||

Line 1: | Line 1: | ||

I see a certain overuse of typeclasses in Haskell libraries. | I see a certain overuse of typeclasses in Haskell libraries. | ||

− | Type classes are not intended for massive re-use of some short identifier or in order to access some [[syntactic sugar]] | + | Type classes are not intended for massive re-use of some short identifier like <hask>fmap</hask> or in order to access some [[syntactic sugar]] |

− | (e.g. [[do notation considered harmful|do notation]] or [[number literal]]s. | + | (e.g. [[do notation considered harmful|do notation]] or [[number literal]]s). |

Instead type classes exist for writing reusable code. | Instead type classes exist for writing reusable code. | ||

Functions written using the <hask>Num</hask> type class like polynomial multiplication work (almost) equally for <hask>Int</hask>, <hask>Integer</hask>, <hask>Rational</hask>, <hask>Float</hask>, <hask>Double</hask> and custom number types. | Functions written using the <hask>Num</hask> type class like polynomial multiplication work (almost) equally for <hask>Int</hask>, <hask>Integer</hask>, <hask>Rational</hask>, <hask>Float</hask>, <hask>Double</hask> and custom number types. | ||

Line 8: | Line 8: | ||

Thus, think twice: | Thus, think twice: | ||

− | Do you really need a <hask>Num</hask> instance for a network port, just in order to be able to write <hask>80</hask> for a port number? | + | Do you really need a <hask>Num</hask> instance for a [http://www.haskell.org/pipermail/haskell-cafe/2009-January/053043.html network port], just in order to be able to write <hask>80</hask> for a port number? |

− | How would sensible definitions of <hask>( | + | How would sensible definitions of <hask>(*)</hask> would look like? |

(Actually, it was not necessary to bundle the number literal feature expressed by the <hask>fromInteger</hask> method | (Actually, it was not necessary to bundle the number literal feature expressed by the <hask>fromInteger</hask> method | ||

with the <hask>(+)</hask> and <hask>(*)</hask> operations, | with the <hask>(+)</hask> and <hask>(*)</hask> operations, | ||

− | and indeed [[ | + | and indeed [[Numeric Prelude]] chooses a different set of operations. |

But it is generally accepted that number literals are reserved for objects that allow some sort of arithmetics.) | But it is generally accepted that number literals are reserved for objects that allow some sort of arithmetics.) | ||

Isn't <hask>port 80</hask> even more comprehensible? | Isn't <hask>port 80</hask> even more comprehensible? | ||

Line 18: | Line 18: | ||

Do you really need a <hask>Functor</hask> instance for the pair type? | Do you really need a <hask>Functor</hask> instance for the pair type? | ||

What distinguishes the second member from the first member? | What distinguishes the second member from the first member? | ||

− | Is the generic pair type the right choice, or should it be | + | Is the generic pair type the right choice, or should it better be a custom type? |

Do you really need a <hask>Monad</hask> instance for writing something to a stream? | Do you really need a <hask>Monad</hask> instance for writing something to a stream? | ||

Or did you define the instance only for the do notation? | Or did you define the instance only for the do notation? | ||

− | + | Please, give the [http://www.haskell.org/pipermail/haskell-cafe/2009-January/053317.html monoid] a try! | |

## Revision as of 15:59, 20 January 2009

I see a certain overuse of typeclasses in Haskell libraries.
Type classes are not intended for massive re-use of some short identifier like `fmap`

or in order to access some syntactic sugar
(e.g. do notation or number literals).
Instead type classes exist for writing reusable code.
Functions written using the `Num`

type class like polynomial multiplication work (almost) equally for `Int`

, `Integer`

, `Rational`

, `Float`

, `Double`

and custom number types.
Functions like `mapM`

and `replicateM`

that only need a `Monad`

constraint can be used for all monads including any combination of monad transformers.

Thus, think twice:

Do you really need a `Num`

instance for a network port, just in order to be able to write `80`

for a port number?
How would sensible definitions of `(*)`

would look like?
(Actually, it was not necessary to bundle the number literal feature expressed by the `fromInteger`

method
with the `(+)`

and `(*)`

operations,
and indeed Numeric Prelude chooses a different set of operations.
But it is generally accepted that number literals are reserved for objects that allow some sort of arithmetics.)
Isn't `port 80`

even more comprehensible?

Do you really need a `Functor`

instance for the pair type?
What distinguishes the second member from the first member?
Is the generic pair type the right choice, or should it better be a custom type?

Do you really need a `Monad`

instance for writing something to a stream?
Or did you define the instance only for the do notation?
Please, give the monoid a try!