【发布时间】:2017-04-25 15:08:29
【问题描述】:
我有一个内部模块,我想为其提供外部 API
module Positive.Internal where
newtype Positive a = Positive { getPositive :: a }
deriving (Eq, Ord)
-- smart constructor
toPositive :: (Num a, Ord a) => a -> Maybe (Positive a)
toPositive a | a <= 0 = Nothing
| otherwise = Just $ Positive a
-- ...
我想隐藏愚蠢的构造函数,并用单向的替换它 模式,因此用户仍然可以模式匹配值,他们只需要使用智能构造函数来使用新值。
由于我希望模式和哑构造函数使用相同的名称,我需要隐藏哑构造函数以防止命名空间冲突。
但是,由于哑构造函数和类型共享名称,因此导入除了哑构造函数之外的所有内容有点棘手。
目前我正在这样做,效果很好:
{-# LANGUAGE PatternSynonyms #-}
module Positive
( module Positive.Internal, pattern Positive
) where
import Positive.Internal (Positive())
import Positive.Internal hiding (Positive)
import qualified Positive.Internal as Internal
pattern Positive :: a -> Positive a
pattern Positive a <- Internal.Positive a
我可以只使用合格的导入来简化我的导入,但我很好奇。
有没有办法在单个导入语句中导入所有 Positive.Internal,除了哑构造函数?
我尝试了hiding (Positive(Positive)),但这隐藏了类型和愚蠢的构造函数。我已经讨论过the wiki,但我没有注意到有任何方法可以区分hiding 列表中的构造函数和类型。
【问题讨论】:
-
我认为将
newtype的构造函数隐藏在内部模块中不是一种选择吗?如果是,您可以将newtype构造函数重命名为(例如)Positive_,将Positive模式同义词移至内部模块并导出。 -
我认为这里已经回答了这个问题:stackoverflow.com/questions/8172548/…从那时起没有任何变化。这个 GHC trac 票建议不要创建新的模式同义词,而只是在当前构造函数上使用
pattern:ghc.haskell.org/trac/ghc/ticket/8753 但不幸的是,这也会导出构造函数,而不仅仅是模式:(因为默认情况下构造函数模式是双向的。 -
为什么要模式和哑构造函数同名?为什么不把愚蠢的构造函数命名为别的呢?无论如何,您的用途都看不到它。还是我误会了……
-
当您尝试在模块中定义与导入模块中的名称相同的名称时,您最好使用
import qualified和限定引用,而不是尝试设置非常挑剔的导入以使隐式不合格的命名空间中包含您想要的内容。 -
@luqui b/c 它使从使用内部 API 到外部 API 的重构变得非常容易。改一下import语句,然后,只要我不使用笨拙的构造函数,我就没事了。