... | @@ -35,7 +35,7 @@ f2 thing_inside = do { res <- thing_inside; return (res, []) } |
... | @@ -35,7 +35,7 @@ f2 thing_inside = do { res <- thing_inside; return (res, []) } |
|
As a rule of thumb, when writing monomorphic code, prefer using a monomorphic function over a typeclass-overloaded one.
|
|
As a rule of thumb, when writing monomorphic code, prefer using a monomorphic function over a typeclass-overloaded one.
|
|
- A monomorphic function communicates information to the programmer, e.g. when reading `map f wibbles` one learns that `wibbles` is a list, as opposed to reading `fmap f wibbles` where one needs to run a mental typechecker to figure out the type of `wibbles` and then infer that `fmap` uses the instance for lists.
|
|
- A monomorphic function communicates information to the programmer, e.g. when reading `map f wibbles` one learns that `wibbles` is a list, as opposed to reading `fmap f wibbles` where one needs to run a mental typechecker to figure out the type of `wibbles` and then infer that `fmap` uses the instance for lists.
|
|
- Monomorphic functions lead to easier-to-understand type errors.
|
|
- Monomorphic functions lead to easier-to-understand type errors.
|
|
- It is easier to refactor code using monomorphic functions, as one can grep/search for a certain function name. Searching for `mapBag` is much, much more helpful than searching for `map`.
|
|
- It is easier to refactor code using monomorphic functions, as one can grep/search for a certain function name. Searching for `mapBag` is much, much more helpful than searching for `fmap`.
|
|
- Overloaded functions rely on typeclass specialisation to be performant, which isn't always reliable and might require additional complexity, in the form of manual `SPECIALISE` annotations and `RULES` pragmas.
|
|
- Overloaded functions rely on typeclass specialisation to be performant, which isn't always reliable and might require additional complexity, in the form of manual `SPECIALISE` annotations and `RULES` pragmas.
|
|
|
|
|
|
Even when one has genuinely polymorphic code, it can be better to write out the code longhand than to reuse a generic abstraction (not always, of course). Sometimes it's better to duplicate some similar code than to try to construct an elaborate generalisation with only two instances. Remember: other people have to be able to quickly understand what you've done, and overuse of abstractions just serves to obscure the *really* tricky stuff, and there's no shortage of that in GHC.
|
|
Even when one has genuinely polymorphic code, it can be better to write out the code longhand than to reuse a generic abstraction (not always, of course). Sometimes it's better to duplicate some similar code than to try to construct an elaborate generalisation with only two instances. Remember: other people have to be able to quickly understand what you've done, and overuse of abstractions just serves to obscure the *really* tricky stuff, and there's no shortage of that in GHC.
|
... | | ... | |