Je comprends pourquoi vous voulez faire cela, mais malheureusement, ce n'est peut-être qu'une illusion que les classes Haskell semblent être "ouvertes" comme vous le dites. Beaucoup de gens pensent que la possibilité de faire cela est un bogue dans la spécification Haskell, pour des raisons que je vais expliquer ci-dessous. Quoi qu'il en soit, si ce n'est vraiment pas approprié pour l'instance, vous devez être déclaré soit dans le module où la classe est déclarée, soit dans le module où le type est déclaré, c'est probablement un signe que vous devriez utiliser un newtype
ou un autre wrapper autour de votre type.
Les raisons pour lesquelles les instances orphelines doivent être évitées sont bien plus profondes que la commodité du compilateur. Ce sujet est plutôt controversé, comme vous pouvez le voir à partir d'autres réponses. Pour équilibrer la discussion, je vais expliquer le point de vue qu'il ne faut jamais, jamais, écrire des instances orphelines, ce qui, je pense, est l'opinion majoritaire parmi les Haskeller expérimentés. Ma propre opinion se situe quelque part au milieu, ce que j'expliquerai à la fin.
Le problème vient du fait que lorsqu'il existe plus d'une déclaration d'instance pour la même classe et le même type, il n'y a pas de mécanisme dans Haskell standard pour spécifier lequel utiliser. Au contraire, le programme est rejeté par le compilateur.
L'effet le plus simple de cela est que vous pourriez avoir un programme parfaitement fonctionnel qui arrêterait soudainement la compilation à cause d'un changement que quelqu'un d'autre fait dans une dépendance éloignée de votre module.
Pire encore, il est possible qu'un programme fonctionnel commence à planter au moment de l'exécution en raison d'un changement distant. Vous pourriez utiliser une méthode dont vous supposez qu'elle provient d'une certaine déclaration d'instance, et elle pourrait être silencieusement remplacée par une instance différente qui est juste assez différente pour que votre programme se mette inexplicablement en panne.
Les personnes qui veulent des garanties que ces problèmes ne leur arriveront jamais doivent suivre la règle selon laquelle si quelqu'un, n'importe où, a déjà déclaré une instance d'une certaine classe pour un certain type, aucune autre instance ne doit plus jamais être déclarée dans un programme écrit par n'importe qui. Bien sûr, il existe une solution de contournement consistant à utiliser a newtype
pour déclarer une nouvelle instance, mais c'est toujours au moins un inconvénient mineur, et parfois majeur. Donc, dans ce sens, ceux qui écrivent intentionnellement des instances orphelines sont plutôt impolis.
Alors, que faut-il faire pour résoudre ce problème? Le camp anti-instance orpheline dit que l'avertissement GHC est un bogue, il doit s'agir d'une erreur qui rejette toute tentative de déclaration d'une instance orpheline. En attendant, nous devons faire preuve d'autodiscipline et les éviter à tout prix.
Comme vous l'avez vu, il y a ceux qui ne s'inquiètent pas autant de ces problèmes potentiels. Ils encouragent en fait l'utilisation d'instances orphelines comme outil de séparation des préoccupations, comme vous le suggérez, et disent qu'il faut simplement s'assurer au cas par cas qu'il n'y a pas de problème. J'ai été assez souvent incommodé par les instances orphelines d'autres personnes pour être convaincu que cette attitude est trop cavalière.
Je pense que la bonne solution serait d'ajouter une extension au mécanisme d'importation de Haskell qui contrôlerait l'importation des instances. Cela ne résoudrait pas complètement les problèmes, mais cela aiderait à protéger nos programmes contre les dommages causés par les instances orphelines qui existent déjà dans le monde. Et puis, avec le temps, je pourrais devenir convaincu que dans certains cas limités, peut-être qu'une instance orpheline pourrait ne pas être si grave. (Et cette tentation même est la raison pour laquelle certains membres du camp anti-orphelin sont opposés à ma proposition.)
Ma conclusion à partir de tout cela est qu'au moins pour le moment, je vous conseillerais fortement d'éviter de déclarer des instances orphelines, d'être prévenant envers les autres si ce n'est pour une autre raison. Utilisez un newtype
.