Как сказать Haskell не импортировать один и тот же экземпляр из двух модулей?
Я использую следующий класс типов:
module T where
class T a where
v :: a
Экземпляр T Int
что я реализовал:
import T
import A (av)
instance T Int where
v = 0
main = putStrLn (av ++ show v)
И модуль, из которого я хочу использовать значение, у которого также есть экземпляр T Int
,
module A where
import T
instance T Int where
v = 0
av = "value from A"
Проблема в том, что это не работает:
$ runghc Main.hs
Main.hs:4:9:
Duplicate instance declarations:
instance T Int -- Defined at Main.hs:4:9-13
instance T Int -- Defined at A.hs:3:9-13
Haskell жалуется, что для одного экземпляра есть 2 объявления. Как я могу сказать ему не импортировать экземпляр из B
или объединить оба экземпляра, или использовать только экземпляр из Main
?
1 ответ
К сожалению, вы не можете контролировать, как экземпляры импортируются и экспортируются; Посмотрите, есть ли у импорта на Haskell побочные эффекты?,
Это означает, что вам придется реорганизовать свой код, чтобы убедиться, что экземпляр определен только в одном файле. В общем случае, лучше всего определять экземпляр в файле, который определяет либо класс, либо тип данных - на самом деле, есть даже предупреждение об "сиротских" экземплярах, которые не следуют этому правилу. (Посмотрите на осиротевшие экземпляры в Haskell для долгого обсуждения того, почему вы должны избегать осиротевших экземпляров.)
Однако, если это невозможно по какой-либо причине, вы все равно можете просто произвольно выбрать один из файлов, чтобы сохранить его, или даже создать новый модуль для импорта всеми файлами, нуждающимися в этом конкретном экземпляре.
В более общем смысле, как бы вы справились с возможностью того, что два экземпляра делали разные вещи, например:
instance T Int where v = 0
{- And in a different file: -}
instance T Int where v = 1
На самом деле не существует очевидного способа устранения двусмысленности этих двух, без существенного изменения работы системы классов типов Haskell.
Поскольку вы сами написали один из примеров, просто удалите его. Поскольку он такой же, как и предопределенный, просто импортируйте этот модуль туда, где вам нужно его использовать.