<div dir="ltr">Lets say there's a type `T` I've imported from a package I don't control. <div><br></div><div>I can easily write new functions to work on `T`.</div><div><br></div><div>For example, I could write:</div><div><br></div><div>f :: T -> T -> T</div><div>f x y = ...</div><div><br></div><div>I've extended T's functionality. No need for newtypes. This makes sense.</div><div><br></div><div>Whilst a newtype in the following case:</div><div><br></div><div>newtype Time = Time Int</div><div><br></div><div>because in this case `Time` is conceptually different to `Int`. For example, you shouldn't multiply two `Time`s</div><div><br></div><div>So in summary, we've just extended T's functionality appropriately, without introducing a newtype.</div><div><br></div><div>But this could be dangerous. Lets say another module writer writes a similar function "f". Then if someone imports their module and ours, there will be a clash. Fortunately the compiler tells about this when it happens, and we can then use qualified imports to workaround the clash. This I'll get back to later.</div><div><br>Now lets say I want to extend T's functionality some more, but this time by making it an instance of class C.</div><div><br></div><div>Class C already exists in a package I don't control.</div><div><br></div><div>Now it would be unreasonable for every class writer to write instances for every possible data type that is appropriate for their class. As you can see, it's an O(n^2) problem, so there will undoubtably be situations where one needs to write instances for data types and classes in separate packages.</div><div><br></div><div>One recommended approach here is to newtype T, like the following:</div><div><br></div><div>newtype MyT = MyT T</div><div><br></div><div>however I find this incredibly ugly. Conceptually, there is no "newtype", and now there's different types of Ts bashing around which really are the same thing. Not only that, they're incompatible, for no good reason. Instead of these different Ts being different types because they're conceptually different things that shouldn't be mixed, the type of these objects depends solely on what operations I want to apply to them. Imagine a rule where:</div><div><br></div><div>f :: T -> T -> T</div><div><br></div><div>was only legal in the module T was defined. If you wanted to define T anywhere else, you'd have to do:</div><div><br></div><div>f :: MyT -> MyT -> MyT</div><div><br></div><div>That's how messy the newtype solution is, it wouldn't be accepted for ordinary functions, and I don't think it's reasonable to apply that messiness to class functions.</div><div><br></div><div>A second approach is an orphan instance. The recommendation here is to put the orphan instances in their own module, so the user can choose to import them. </div><div><br></div><div>This may works ok if your user is writing an executable. But what if your user is writing a library themselves. But once, you, or your user, directly uses one of the instances, they need to import it, and they pollute the global instance namespace for anyone that uses their package.</div><div><br></div><div>This is okay if you're the only person doing it, but I think it's reasonable to say that if your practices would be bad if someone else was doing them also, then they're a bad practice. Indeed, if someone else writes their own instances and they clash with yours, people simply can't use your package and their package in the same program. This is bad.</div><div><br></div><div>In the simple "function" case. We deal with the clash of two functions named "f" using qualified imports. We can't do that instances, nor can we even hide one of the instances. </div><div><br></div><div>So to recap here we've tried:</div><div><br></div><div>(1) Copying the data type. We've decided this has lots of problems.</div><div>(2) Just making an orphan instance. This has serious problems too.</div><div><br></div><div>I want to suggest a third option:</div><div><br></div><div>(3) Copying the class.</div><div><br></div><div>What would this involve:</div><div><br></div><div>a) Making a new class (say C1), with the same class methods as the existing one (say C).</div><div>b) Making an instance of the class like so:</div><div><br></div><div>instance (C x) => C1 x where</div><div>  f = ModuleC.f<br>  ...<br><br></div><div>which forwards all the calls to C. <br><br>c) Add your new instances to C1 (these will overlap with the above but they will be more specific so with overlapping instances this is allowed).</div><div><br></div><div>Now if your users want to use your instances, they import C1. They can still use the data type T as usual on the old instances, or on any existing functions defined on T directly.<br><br>The big question is, what if someone else does this, and creates C2?</div><div><br></div><div>Then they'll be a clash. But in this case, classes, unlike instances, can be explicitly imported and qualified. Your packages won't be impossible to use together, just the user will have to import one of them qualified. That's acceptable, we understand we have to do this sometimes with clashing function names too.<br><br>So I guess my questions are:</div><div><br></div><div>What do you think of my analysis? Are there parts that are incorrect?</div><div>What do you think of my solution? Is there reasons why it is not as good as the "newtype" or "orphan instances" approach?</div><div>Is there a way to make my solution easier to implement, i.e. less typing?</div></div>