如何导入模块隐藏子模块或实例?
How to import module hiding submodules or instances?
使用此代码
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.Trans.Error
.
的 Control.Monad.State
,错误就会消失
如何从那里导入 Control.Monad.State
隐藏 Control.Monad.Trans.Error
或隐藏 Either
个 Alternative
和 MonadPlus
实例?
我用GHC-7.10.2
Haskell 2010 report,第 5.4 节说:
Instance declarations cannot be explicitly named on import or export
lists. All instances in scope within a module are always exported and
any import brings all instances in from the imported module. Thus, an
instance declaration is in scope if and only if a chain of import
declarations leads to the module containing the instance declaration.
所以标准规定你不能做你想做的事。
原因是允许这样做可能会创建混合不同实例的程序,从而产生不正确的结果。
例如参见Explicitly import instances。
有些扩展(例如 GeneralizedNewtypeDeriving
,参见 Breaking Data.Set integrity without GeneralizedNewtypeDeriving)允许混合实例,即使 export/import 列表中没有实例。
事实上 GHC 并没有 100% 遵守这方面的标准并允许格式错误的程序。它不会全局检查实例声明,但只有一个实例在需要它的范围内。参见 this answer。
在您的情况下,您可能应该在 Either
周围使用一些 newtype
以避免混合实例:
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
。
使用此代码
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.Trans.Error
.
Control.Monad.State
,错误就会消失
如何从那里导入 Control.Monad.State
隐藏 Control.Monad.Trans.Error
或隐藏 Either
个 Alternative
和 MonadPlus
实例?
我用GHC-7.10.2
Haskell 2010 report,第 5.4 节说:
Instance declarations cannot be explicitly named on import or export lists. All instances in scope within a module are always exported and any import brings all instances in from the imported module. Thus, an instance declaration is in scope if and only if a chain of
import
declarations leads to the module containing the instance declaration.
所以标准规定你不能做你想做的事。
原因是允许这样做可能会创建混合不同实例的程序,从而产生不正确的结果。
例如参见Explicitly import instances。
有些扩展(例如 GeneralizedNewtypeDeriving
,参见 Breaking Data.Set integrity without GeneralizedNewtypeDeriving)允许混合实例,即使 export/import 列表中没有实例。
事实上 GHC 并没有 100% 遵守这方面的标准并允许格式错误的程序。它不会全局检查实例声明,但只有一个实例在需要它的范围内。参见 this answer。
在您的情况下,您可能应该在 Either
周围使用一些 newtype
以避免混合实例:
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
。