Suppose I have some generic function
genericFunc :: a -> b
genericFunc x = doSomeHardWork
But for a particular type, there is a much more efficient way that genericFunc could be done.
genericFunc :: ParticularType -> b
genericFunc x = doSomeEasyWork
What is the best way to combine these two function bodies into the same genericFunc, such that when used on ParticularType, it will doSomeEasyWork, but when used on other types, it will doSomeHardWork? I’m specifically excluding the option of using a different name, or different modules.
I believe this can be done with a typeclass, but I am more interested in solutions that use language pragmas. I have a vague inkling that this can be done with language pragmas but I have no idea how. Bonus points if you compare and contrast these approaches, and/or any other possible approaches.
This can be done with type classes by defining the general-purpose method in the class definition and overriding it in an instance. The overridden function will always be used.
An alternative supported by GHC is to use a rewrite rule. The rewrite rule tells GHC to replace one expression by another whenever possible. If the replacement is ill-typed, it will not be done, so you can use this to replace a function by a specialized version. The rewrite rule is given by a
{-# RULES #-}pragma.Rewrite rules are performed at the discretion of the compiler, so the specialized function may or may not be called in any given situation. For example, the rewrite may depend on whether the compiler decides to inline a function: