Я понимаю, почему вы хотите это сделать, но, к сожалению, это может быть только иллюзией, что классы на Хаскеле кажутся "открытыми" в том смысле, как вы говорите. Многие люди считают, что возможность сделать это является ошибкой в спецификации Haskell, по причинам, которые я объясню ниже. В любом случае, если это действительно не подходит для экземпляра, вам нужно объявить либо в модуле, где объявлен класс, либо в модуле, где объявлен тип, это, вероятно, признак того, что вы должны использовать newtype
или какая-то другая обертка вокруг вашего типа.
Причины, по которым нужно избегать появления бесхозных экземпляров, гораздо глубже, чем удобство компилятора. Эта тема довольно противоречива, как вы можете видеть из других ответов. Чтобы уравновесить дискуссию, я собираюсь объяснить точку зрения о том, что никогда и никогда не следует писать бесхозные экземпляры, что, на мой взгляд, является мнением большинства среди опытных хаскеллеров. Мое собственное мнение где-то посередине, и я объясню в конце.
Проблема связана с тем фактом, что, когда существует несколько объявлений экземпляров для одного и того же класса и типа, в стандартном Haskell нет механизма, определяющего, какой из них использовать. Скорее программа отклонена компилятором.
Самый простой эффект этого заключается в том, что у вас может быть отлично работающая программа, которая внезапно прекратит компиляцию из-за изменений, внесенных кем-то другим в какую-то удаленную зависимость вашего модуля.
Что еще хуже, работающая программа может запустить , сбой во время выполнения из-за отдаленного изменения. Вы можете использовать метод, который, как вы предполагаете, происходит из определенного объявления экземпляра, и его можно было бы тихо заменить другим экземпляром, достаточно отличающимся, чтобы заставить вашу программу необъяснимым образом зависать.
Люди, которые хотят гарантировать, что эти проблемы никогда не возникнут, должны следовать правилу, согласно которому, если кто-либо где-либо когда-либо объявлял экземпляр определенного класса для определенного типа, ни один другой экземпляр никогда не должен объявляться снова в любая программа, написанная кем-либо. Конечно, есть обходной путь использования newtype
для объявления нового экземпляра, но это всегда, по крайней мере, незначительное неудобство, а иногда и серьезное.
Поэтому в этом смысле те, кто намеренно пишут бесхозные экземпляры, довольно невежливы.
Так что же делать с этой проблемой? Лагерь анти-сироты говорит, что предупреждение GHC - это ошибка, это должна быть ошибка, которая отклоняет любую попытку объявить экземпляр-сироту. Тем временем мы должны проявлять самодисциплину и избегать их любой ценой.
Как вы видели, есть те, кто не так обеспокоен этими потенциальными проблемами. Как вы предлагаете, они на самом деле поощряют использование бесхозных экземпляров в качестве инструмента для разделения интересов и говорят, что нужно просто в каждом конкретном случае убедиться, что проблем нет. Я был достаточно неудобен, когда другие люди осиротели, чтобы быть уверенным, что это отношение слишком кавалерно.
Я думаю, что правильным решением было бы добавить расширение к механизму импорта Haskell, который контролировал бы импорт экземпляров. Это не решило бы проблемы полностью, но помогло бы защитить наши программы от ущерба, нанесенного сиротским инстанциям, которые уже существуют в мире. И потом, со временем, я мог бы убедиться, что в некоторых ограниченных случаях, возможно, случай с сиротой не так уж и плох. (И именно это искушение является причиной того, что некоторые в лагере против сирот выступают против моего предложения.)
Мой вывод из всего этого состоит в том, что, по крайней мере, на данный момент, я настоятельно рекомендую вам избегать объявления каких-либо сиротских случаев, чтобы быть внимательным к другим, если ни по какой другой причине. Используйте newtype
.