2015-08-29 2 views
3

С помощью этого кодаКак импортировать модуль, скрывающий подмодули или экземпляры?

import Control.Monad 
import Control.Applicative 
import Control.Monad.State 

class DefVal a where 
    defVal :: a 

instance (DefVal a) => Alternative (Either a) where 
    empty = Left defVal 
    (Left _) <|> x = x 
    x  <|> _ = x 

instance (DefVal a) => MonadPlus (Either a) where 
    mzero = empty 
    mplus = (<|>) 

newtype ErrString = ErrString { toString :: String } 
    deriving Show 

instance DefVal ErrString where 
    defVal = ErrString "Default Error String" 

я получаю ошибки:

Duplicate instance declarations: 
    instance DefVal a => Alternative (Either a) 
    -- Defined at main.hs:10:10 
    instance Control.Monad.Trans.Error.Error e => 
      Alternative (Either e) 
    -- Defined in ‘Control.Monad.Trans.Error’ 

Duplicate instance declarations: 
    instance DefVal a => MonadPlus (Either a) 
    -- Defined at main.hs:15:10 
    instance Control.Monad.Trans.Error.Error e => MonadPlus (Either e) 
    -- Defined in ‘Control.Monad.Trans.Error’ 

Ошибка исчезает, если удалить Control.Monad.State, который импортирует Control.Monad.Trans.Error.

Как я могу импортировать Control.Monad.StateControl.Monad.Trans.Error скрывается или скрыть Either экземпляры Alternative и MonadPlus оттуда?

Я использую GHC-7.10.2

+1

AFAIK в настоящее время абсолютно невозможно ссылаться на экземпляры в списках импорта/экспорта. Не повезло тебе. См. Http://stackoverflow.com/questions/8728596/explicitly-import-instances – Bakuriu

ответ

4

Haskell 2010 report, раздел 5.4 говорит: декларации

экземпляра не может быть явно указан на импорт или экспорт списков. Все экземпляры в области внутри модуля: всегда экспортировано и любой импорт приносит все экземпляры из импортированного модуля. Таким образом, объявление экземпляра является областью действия тогда и только тогда, когда цепочка из import деклараций приводит к модулю, содержащему объявление экземпляра.

Так что продиктована стандартным, что вы не может делать то, что вы пытаетесь сделать.

Причина в том, что, разрешив это, можно было бы создавать программы, которые смешивают разные экземпляры, производя неправильные результаты.

См., Например, Explicitly import instances.

Существует несколько расширений (например, GeneralizedNewtypeDeriving, см. Breaking Data.Set integrity without GeneralizedNewtypeDeriving), которые позволяют смешивать экземпляры даже без экземпляров в списках экспорта/импорта.

Фактически GHC уже не придерживается стандарта 100% по этому стандарту и допускает искаженные программы. Он не проверяет глобальные запросы для экземпляров, но только то, что только один экземпляр находится в области, где это необходимо. См. this answer.


В вашем случае вы, вероятно, следует использовать некоторые newtype вокруг Either, чтобы избежать смешивания экземпляров:

newtype MyEither e a = MyEither {runMyEither :: Either e a} 


instance (DefVal a) => Alternative (MyEither a) where 
    empty = MyEither (Left defVal) 
    (MyEither (Left _)) <|> x = x 
    x     <|> _ = x 

instance (DefVal a) => MonadPlus (MyEither a) where 
    mzero = empty 
    mplus = (<|>) 

Кто хочет значение x ::Either a b действовать как x :: MyEither a b может просто сделать MyEither x, а затем использовать runMyEither на результат.

+0

Если экземпляры всегда импортируются, скрытие модулей (если это возможно) не скроет их. Спасибо за совет 'newtype'! – wowofbob

Смежные вопросы